LLVM 24.0.0git
SILoadStoreOptimizer.cpp
Go to the documentation of this file.
1//===- SILoadStoreOptimizer.cpp -------------------------------------------===//
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 tries to fuse DS instructions with close by immediate offsets.
10// This will fuse operations such as
11// ds_read_b32 v0, v2 offset:16
12// ds_read_b32 v1, v2 offset:32
13// ==>
14// ds_read2_b32 v[0:1], v2, offset0:4 offset1:8
15//
16// The same is done for certain SMEM and VMEM opcodes, e.g.:
17// s_buffer_load_dword s4, s[0:3], 4
18// s_buffer_load_dword s5, s[0:3], 8
19// ==>
20// s_buffer_load_dwordx2 s[4:5], s[0:3], 4
21//
22// This pass also tries to promote constant offset to the immediate by
23// adjusting the base. It tries to use a base from the nearby instructions that
24// allows it to have a 13bit constant offset and then promotes the 13bit offset
25// to the immediate.
26// E.g.
27// s_movk_i32 s0, 0x1800
28// v_add_co_u32_e32 v0, vcc, s0, v2
29// v_addc_co_u32_e32 v1, vcc, 0, v6, vcc
30//
31// s_movk_i32 s0, 0x1000
32// v_add_co_u32_e32 v5, vcc, s0, v2
33// v_addc_co_u32_e32 v6, vcc, 0, v6, vcc
34// global_load_dwordx2 v[5:6], v[5:6], off
35// global_load_dwordx2 v[0:1], v[0:1], off
36// =>
37// s_movk_i32 s0, 0x1000
38// v_add_co_u32_e32 v5, vcc, s0, v2
39// v_addc_co_u32_e32 v6, vcc, 0, v6, vcc
40// global_load_dwordx2 v[5:6], v[5:6], off
41// global_load_dwordx2 v[0:1], v[5:6], off offset:2048
42//
43// Future improvements:
44//
45// - This is currently missing stores of constants because loading
46// the constant into the data register is placed between the stores, although
47// this is arguably a scheduling problem.
48//
49// - Live interval recomputing seems inefficient. This currently only matches
50// one pair, and recomputes live intervals and moves on to the next pair. It
51// would be better to compute a list of all merges that need to occur.
52//
53// - With a list of instructions to process, we can also merge more. If a
54// cluster of loads have offsets that are too large to fit in the 8-bit
55// offsets, but are close enough to fit in the 8 bits, we can add to the base
56// pointer and use the new reduced offsets.
57//
58//===----------------------------------------------------------------------===//
59
61#include "AMDGPU.h"
62#include "GCNSubtarget.h"
64#include "SIDefines.h"
69
70using namespace llvm;
71
72#define DEBUG_TYPE "si-load-store-opt"
73
74namespace {
75enum InstClassEnum {
76 UNKNOWN,
77 DS_READ,
78 DS_WRITE,
79 S_BUFFER_LOAD_IMM,
80 S_BUFFER_LOAD_SGPR_IMM,
81 S_LOAD_IMM,
82 BUFFER_LOAD,
83 BUFFER_STORE,
84 MIMG,
85 TBUFFER_LOAD,
86 TBUFFER_STORE,
87 GLOBAL_LOAD_SADDR,
88 GLOBAL_STORE_SADDR,
89 FLAT_LOAD,
90 FLAT_STORE,
91 FLAT_LOAD_SADDR,
92 FLAT_STORE_SADDR,
93 GLOBAL_LOAD, // GLOBAL_LOAD/GLOBAL_STORE are never used as the InstClass of
94 GLOBAL_STORE // any CombineInfo, they are only ever returned by
95 // getCommonInstClass.
96};
97
98struct AddressRegs {
99 unsigned char NumVAddrs = 0;
100 bool SBase = false;
101 bool SRsrc = false;
102 bool SOffset = false;
103 bool SAddr = false;
104 bool VAddr = false;
105 bool Addr = false;
106 bool SSamp = false;
107};
108
109// GFX10 image_sample instructions can have 12 vaddrs + srsrc + ssamp.
110const unsigned MaxAddressRegs = 12 + 1 + 1;
111
112class SILoadStoreOptimizer {
113 struct CombineInfo {
115 unsigned EltSize;
116 unsigned Offset;
117 unsigned Width;
118 unsigned Format;
119 unsigned BaseOff;
120 unsigned DMask;
121 InstClassEnum InstClass;
122 unsigned CPol = 0;
123 const TargetRegisterClass *DataRC;
124 bool UseST64;
125 int AddrIdx[MaxAddressRegs];
126 const MachineOperand *AddrReg[MaxAddressRegs];
127 unsigned NumAddresses;
128 unsigned Order;
129
130 bool hasSameBaseAddress(const CombineInfo &CI) {
131 if (NumAddresses != CI.NumAddresses)
132 return false;
133
134 const MachineInstr &MI = *CI.I;
135 for (unsigned i = 0; i < NumAddresses; i++) {
136 const MachineOperand &AddrRegNext = MI.getOperand(AddrIdx[i]);
137
138 if (AddrReg[i]->isImm() || AddrRegNext.isImm()) {
139 if (AddrReg[i]->isImm() != AddrRegNext.isImm() ||
140 AddrReg[i]->getImm() != AddrRegNext.getImm()) {
141 return false;
142 }
143 continue;
144 }
145
146 // Check same base pointer. Be careful of subregisters, which can occur
147 // with vectors of pointers.
148 if (AddrReg[i]->getReg() != AddrRegNext.getReg() ||
149 AddrReg[i]->getSubReg() != AddrRegNext.getSubReg()) {
150 return false;
151 }
152 }
153 return true;
154 }
155
156 bool hasMergeableAddress(const MachineRegisterInfo &MRI) {
157 for (unsigned i = 0; i < NumAddresses; ++i) {
158 const MachineOperand *AddrOp = AddrReg[i];
159 // Immediates are always OK.
160 if (AddrOp->isImm())
161 continue;
162
163 // Don't try to merge addresses that aren't either immediates or registers.
164 // TODO: Should be possible to merge FrameIndexes and maybe some other
165 // non-register
166 if (!AddrOp->isReg())
167 return false;
168
169 // TODO: We should be able to merge instructions with other physical reg
170 // addresses too.
171 if (AddrOp->getReg().isPhysical() &&
172 AddrOp->getReg() != AMDGPU::SGPR_NULL)
173 return false;
174
175 // If an address has only one use then there will be no other
176 // instructions with the same address, so we can't merge this one.
177 if (MRI.hasOneNonDBGUse(AddrOp->getReg()))
178 return false;
179 }
180 return true;
181 }
182
183 void setMI(MachineBasicBlock::iterator MI, const SILoadStoreOptimizer &LSO);
184
185 // Compare by pointer order.
186 bool operator<(const CombineInfo& Other) const {
187 return (InstClass == MIMG) ? DMask < Other.DMask : Offset < Other.Offset;
188 }
189 };
190
191 struct BaseRegisters {
192 Register LoReg;
193 Register HiReg;
194
195 unsigned LoSubReg = 0;
196 unsigned HiSubReg = 0;
197 // True when using V_ADD_U64_e64 pattern
198 bool UseV64Pattern = false;
199 };
200
201 struct MemAddress {
202 BaseRegisters Base;
203 int64_t Offset = 0;
204 };
205
206 using MemInfoMap = DenseMap<MachineInstr *, MemAddress>;
207
208private:
209 MachineFunction *MF = nullptr;
210 const GCNSubtarget *STM = nullptr;
211 const SIInstrInfo *TII = nullptr;
212 const SIRegisterInfo *TRI = nullptr;
213 MachineRegisterInfo *MRI = nullptr;
214 AliasAnalysis *AA = nullptr;
215 bool OptimizeAgain;
216
217 bool canSwapInstructions(const DenseSet<Register> &ARegDefs,
218 const DenseSet<Register> &ARegUses,
219 const MachineInstr &A, const MachineInstr &B) const;
220 static bool dmasksCanBeCombined(const CombineInfo &CI,
221 const SIInstrInfo &TII,
222 const CombineInfo &Paired);
223 static bool offsetsCanBeCombined(CombineInfo &CI, const GCNSubtarget &STI,
224 CombineInfo &Paired, bool Modify = false);
225 static bool widthsFit(const GCNSubtarget &STI, const CombineInfo &CI,
226 const CombineInfo &Paired);
227 unsigned getNewOpcode(const CombineInfo &CI, const CombineInfo &Paired);
228 static std::pair<unsigned, unsigned> getSubRegIdxs(const CombineInfo &CI,
229 const CombineInfo &Paired);
230 const TargetRegisterClass *
231 getTargetRegisterClass(const CombineInfo &CI,
232 const CombineInfo &Paired) const;
233 const TargetRegisterClass *getDataRegClass(const MachineInstr &MI) const;
234
235 CombineInfo *checkAndPrepareMerge(CombineInfo &CI, CombineInfo &Paired);
236
237 void copyToDestRegs(CombineInfo &CI, CombineInfo &Paired,
238 MachineBasicBlock::iterator InsertBefore,
239 const DebugLoc &DL, AMDGPU::OpName OpName,
240 Register DestReg) const;
241 Register copyFromSrcRegs(CombineInfo &CI, CombineInfo &Paired,
242 MachineBasicBlock::iterator InsertBefore,
243 const DebugLoc &DL, AMDGPU::OpName OpName) const;
244
245 unsigned read2Opcode(unsigned EltSize) const;
246 unsigned read2ST64Opcode(unsigned EltSize) const;
248 mergeRead2Pair(CombineInfo &CI, CombineInfo &Paired,
249 MachineBasicBlock::iterator InsertBefore);
250
251 unsigned write2Opcode(unsigned EltSize) const;
252 unsigned write2ST64Opcode(unsigned EltSize) const;
253 unsigned getWrite2Opcode(const CombineInfo &CI) const;
254
256 mergeWrite2Pair(CombineInfo &CI, CombineInfo &Paired,
257 MachineBasicBlock::iterator InsertBefore);
259 mergeImagePair(CombineInfo &CI, CombineInfo &Paired,
260 MachineBasicBlock::iterator InsertBefore);
262 mergeSMemLoadImmPair(CombineInfo &CI, CombineInfo &Paired,
263 MachineBasicBlock::iterator InsertBefore);
265 mergeBufferLoadPair(CombineInfo &CI, CombineInfo &Paired,
266 MachineBasicBlock::iterator InsertBefore);
268 mergeBufferStorePair(CombineInfo &CI, CombineInfo &Paired,
269 MachineBasicBlock::iterator InsertBefore);
271 mergeTBufferLoadPair(CombineInfo &CI, CombineInfo &Paired,
272 MachineBasicBlock::iterator InsertBefore);
274 mergeTBufferStorePair(CombineInfo &CI, CombineInfo &Paired,
275 MachineBasicBlock::iterator InsertBefore);
277 mergeFlatLoadPair(CombineInfo &CI, CombineInfo &Paired,
278 MachineBasicBlock::iterator InsertBefore);
280 mergeFlatStorePair(CombineInfo &CI, CombineInfo &Paired,
281 MachineBasicBlock::iterator InsertBefore);
282
283 void updateBaseAndOffset(MachineInstr &I, Register NewBase,
284 int32_t NewOffset) const;
285 void updateAsyncLDSAddress(MachineInstr &MI, int32_t OffsetDiff) const;
286 Register computeBase(MachineInstr &MI, const MemAddress &Addr) const;
287 MachineOperand createRegOrImm(int32_t Val, MachineInstr &MI) const;
288 bool processBaseWithConstOffset64(MachineInstr *AddDef,
289 const MachineOperand &Base,
290 MemAddress &Addr) const;
291 void processBaseWithConstOffset(const MachineOperand &Base, MemAddress &Addr) const;
292 /// Promotes constant offset to the immediate by adjusting the base. It
293 /// tries to use a base from the nearby instructions that allows it to have
294 /// a 13bit constant offset which gets promoted to the immediate.
295 bool promoteConstantOffsetToImm(MachineInstr &CI,
296 MemInfoMap &Visited,
297 SmallPtrSet<MachineInstr *, 4> &Promoted) const;
298 void addInstToMergeableList(const CombineInfo &CI,
299 std::list<std::list<CombineInfo> > &MergeableInsts) const;
300
301 std::pair<MachineBasicBlock::iterator, bool> collectMergeableInsts(
303 MemInfoMap &Visited, SmallPtrSet<MachineInstr *, 4> &AnchorList,
304 std::list<std::list<CombineInfo>> &MergeableInsts) const;
305
306 static MachineMemOperand *combineKnownAdjacentMMOs(const CombineInfo &CI,
307 const CombineInfo &Paired);
308
309 static InstClassEnum getCommonInstClass(const CombineInfo &CI,
310 const CombineInfo &Paired);
311
312 bool optimizeInstsWithSameBaseAddr(std::list<CombineInfo> &MergeList,
313 bool &OptimizeListAgain);
314 bool optimizeBlock(std::list<std::list<CombineInfo> > &MergeableInsts);
315
316public:
317 SILoadStoreOptimizer(AliasAnalysis *AA) : AA(AA) {}
318 bool run(MachineFunction &MF);
319};
320
321class SILoadStoreOptimizerLegacy : public MachineFunctionPass {
322public:
323 static char ID;
324
325 SILoadStoreOptimizerLegacy() : MachineFunctionPass(ID) {}
326
327 bool runOnMachineFunction(MachineFunction &MF) override;
328
329 StringRef getPassName() const override { return "SI Load Store Optimizer"; }
330
331 void getAnalysisUsage(AnalysisUsage &AU) const override {
332 AU.setPreservesCFG();
335
337 }
338
339 MachineFunctionProperties getRequiredProperties() const override {
340 return MachineFunctionProperties().setIsSSA();
341 }
342};
343
344static unsigned getOpcodeWidth(const MachineInstr &MI, const SIInstrInfo &TII) {
345 const unsigned Opc = MI.getOpcode();
346
347 if (TII.isMUBUF(Opc)) {
348 // FIXME: Handle d16 correctly
350 }
351 if (TII.isImage(MI)) {
352 uint64_t DMaskImm =
353 TII.getNamedOperand(MI, AMDGPU::OpName::dmask)->getImm();
354 return llvm::popcount(DMaskImm);
355 }
356 if (TII.isMTBUF(Opc)) {
358 }
359
360 switch (Opc) {
361 case AMDGPU::S_BUFFER_LOAD_DWORD_IMM:
362 case AMDGPU::S_BUFFER_LOAD_DWORD_SGPR_IMM:
363 case AMDGPU::S_LOAD_DWORD_IMM:
364 case AMDGPU::GLOBAL_LOAD_DWORD:
365 case AMDGPU::GLOBAL_LOAD_DWORD_SADDR:
366 case AMDGPU::GLOBAL_STORE_DWORD:
367 case AMDGPU::GLOBAL_STORE_DWORD_SADDR:
368 case AMDGPU::FLAT_LOAD_DWORD:
369 case AMDGPU::FLAT_STORE_DWORD:
370 case AMDGPU::FLAT_LOAD_DWORD_SADDR:
371 case AMDGPU::FLAT_STORE_DWORD_SADDR:
372 return 1;
373 case AMDGPU::S_BUFFER_LOAD_DWORDX2_IMM:
374 case AMDGPU::S_BUFFER_LOAD_DWORDX2_SGPR_IMM:
375 case AMDGPU::S_BUFFER_LOAD_DWORDX2_IMM_ec:
376 case AMDGPU::S_BUFFER_LOAD_DWORDX2_SGPR_IMM_ec:
377 case AMDGPU::S_LOAD_DWORDX2_IMM:
378 case AMDGPU::S_LOAD_DWORDX2_IMM_ec:
379 case AMDGPU::GLOBAL_LOAD_DWORDX2:
380 case AMDGPU::GLOBAL_LOAD_DWORDX2_SADDR:
381 case AMDGPU::GLOBAL_STORE_DWORDX2:
382 case AMDGPU::GLOBAL_STORE_DWORDX2_SADDR:
383 case AMDGPU::FLAT_LOAD_DWORDX2:
384 case AMDGPU::FLAT_STORE_DWORDX2:
385 case AMDGPU::FLAT_LOAD_DWORDX2_SADDR:
386 case AMDGPU::FLAT_STORE_DWORDX2_SADDR:
387 return 2;
388 case AMDGPU::S_BUFFER_LOAD_DWORDX3_IMM:
389 case AMDGPU::S_BUFFER_LOAD_DWORDX3_SGPR_IMM:
390 case AMDGPU::S_BUFFER_LOAD_DWORDX3_IMM_ec:
391 case AMDGPU::S_BUFFER_LOAD_DWORDX3_SGPR_IMM_ec:
392 case AMDGPU::S_LOAD_DWORDX3_IMM:
393 case AMDGPU::S_LOAD_DWORDX3_IMM_ec:
394 case AMDGPU::GLOBAL_LOAD_DWORDX3:
395 case AMDGPU::GLOBAL_LOAD_DWORDX3_SADDR:
396 case AMDGPU::GLOBAL_STORE_DWORDX3:
397 case AMDGPU::GLOBAL_STORE_DWORDX3_SADDR:
398 case AMDGPU::FLAT_LOAD_DWORDX3:
399 case AMDGPU::FLAT_STORE_DWORDX3:
400 case AMDGPU::FLAT_LOAD_DWORDX3_SADDR:
401 case AMDGPU::FLAT_STORE_DWORDX3_SADDR:
402 return 3;
403 case AMDGPU::S_BUFFER_LOAD_DWORDX4_IMM:
404 case AMDGPU::S_BUFFER_LOAD_DWORDX4_SGPR_IMM:
405 case AMDGPU::S_BUFFER_LOAD_DWORDX4_IMM_ec:
406 case AMDGPU::S_BUFFER_LOAD_DWORDX4_SGPR_IMM_ec:
407 case AMDGPU::S_LOAD_DWORDX4_IMM:
408 case AMDGPU::S_LOAD_DWORDX4_IMM_ec:
409 case AMDGPU::GLOBAL_LOAD_DWORDX4:
410 case AMDGPU::GLOBAL_LOAD_DWORDX4_SADDR:
411 case AMDGPU::GLOBAL_STORE_DWORDX4:
412 case AMDGPU::GLOBAL_STORE_DWORDX4_SADDR:
413 case AMDGPU::FLAT_LOAD_DWORDX4:
414 case AMDGPU::FLAT_STORE_DWORDX4:
415 case AMDGPU::FLAT_LOAD_DWORDX4_SADDR:
416 case AMDGPU::FLAT_STORE_DWORDX4_SADDR:
417 return 4;
418 case AMDGPU::S_BUFFER_LOAD_DWORDX8_IMM:
419 case AMDGPU::S_BUFFER_LOAD_DWORDX8_SGPR_IMM:
420 case AMDGPU::S_BUFFER_LOAD_DWORDX8_IMM_ec:
421 case AMDGPU::S_BUFFER_LOAD_DWORDX8_SGPR_IMM_ec:
422 case AMDGPU::S_LOAD_DWORDX8_IMM:
423 case AMDGPU::S_LOAD_DWORDX8_IMM_ec:
424 return 8;
425 case AMDGPU::DS_READ_B32:
426 case AMDGPU::DS_READ_B32_gfx9:
427 case AMDGPU::DS_WRITE_B32:
428 case AMDGPU::DS_WRITE_B32_gfx9:
429 return 1;
430 case AMDGPU::DS_READ_B64:
431 case AMDGPU::DS_READ_B64_gfx9:
432 case AMDGPU::DS_WRITE_B64:
433 case AMDGPU::DS_WRITE_B64_gfx9:
434 return 2;
435 default:
436 return 0;
437 }
438}
439
440/// Maps instruction opcode to enum InstClassEnum.
441static InstClassEnum getInstClass(unsigned Opc, const SIInstrInfo &TII) {
442 switch (Opc) {
443 default:
444 if (TII.isMUBUF(Opc)) {
446 default:
447 return UNKNOWN;
448 case AMDGPU::BUFFER_LOAD_DWORD_BOTHEN:
449 case AMDGPU::BUFFER_LOAD_DWORD_BOTHEN_exact:
450 case AMDGPU::BUFFER_LOAD_DWORD_IDXEN:
451 case AMDGPU::BUFFER_LOAD_DWORD_IDXEN_exact:
452 case AMDGPU::BUFFER_LOAD_DWORD_OFFEN:
453 case AMDGPU::BUFFER_LOAD_DWORD_OFFEN_exact:
454 case AMDGPU::BUFFER_LOAD_DWORD_OFFSET:
455 case AMDGPU::BUFFER_LOAD_DWORD_OFFSET_exact:
456 case AMDGPU::BUFFER_LOAD_DWORD_VBUFFER_BOTHEN:
457 case AMDGPU::BUFFER_LOAD_DWORD_VBUFFER_BOTHEN_exact:
458 case AMDGPU::BUFFER_LOAD_DWORD_VBUFFER_IDXEN:
459 case AMDGPU::BUFFER_LOAD_DWORD_VBUFFER_IDXEN_exact:
460 case AMDGPU::BUFFER_LOAD_DWORD_VBUFFER_OFFEN:
461 case AMDGPU::BUFFER_LOAD_DWORD_VBUFFER_OFFEN_exact:
462 case AMDGPU::BUFFER_LOAD_DWORD_VBUFFER_OFFSET:
463 case AMDGPU::BUFFER_LOAD_DWORD_VBUFFER_OFFSET_exact:
464 return BUFFER_LOAD;
465 case AMDGPU::BUFFER_STORE_DWORD_BOTHEN:
466 case AMDGPU::BUFFER_STORE_DWORD_BOTHEN_exact:
467 case AMDGPU::BUFFER_STORE_DWORD_IDXEN:
468 case AMDGPU::BUFFER_STORE_DWORD_IDXEN_exact:
469 case AMDGPU::BUFFER_STORE_DWORD_OFFEN:
470 case AMDGPU::BUFFER_STORE_DWORD_OFFEN_exact:
471 case AMDGPU::BUFFER_STORE_DWORD_OFFSET:
472 case AMDGPU::BUFFER_STORE_DWORD_OFFSET_exact:
473 case AMDGPU::BUFFER_STORE_DWORD_VBUFFER_BOTHEN:
474 case AMDGPU::BUFFER_STORE_DWORD_VBUFFER_BOTHEN_exact:
475 case AMDGPU::BUFFER_STORE_DWORD_VBUFFER_IDXEN:
476 case AMDGPU::BUFFER_STORE_DWORD_VBUFFER_IDXEN_exact:
477 case AMDGPU::BUFFER_STORE_DWORD_VBUFFER_OFFEN:
478 case AMDGPU::BUFFER_STORE_DWORD_VBUFFER_OFFEN_exact:
479 case AMDGPU::BUFFER_STORE_DWORD_VBUFFER_OFFSET:
480 case AMDGPU::BUFFER_STORE_DWORD_VBUFFER_OFFSET_exact:
481 return BUFFER_STORE;
482 }
483 }
484 if (TII.isImage(Opc)) {
485 // Ignore instructions encoded without vaddr.
486 if (!AMDGPU::hasNamedOperand(Opc, AMDGPU::OpName::vaddr) &&
487 !AMDGPU::hasNamedOperand(Opc, AMDGPU::OpName::vaddr0))
488 return UNKNOWN;
489 // Ignore BVH instructions
491 return UNKNOWN;
492 // TODO: Support IMAGE_GET_RESINFO and IMAGE_GET_LOD.
493 if (TII.get(Opc).mayStore() || !TII.get(Opc).mayLoad() ||
494 TII.isGather4(Opc))
495 return UNKNOWN;
496 return MIMG;
497 }
498 if (TII.isMTBUF(Opc)) {
500 default:
501 return UNKNOWN;
502 case AMDGPU::TBUFFER_LOAD_FORMAT_X_BOTHEN:
503 case AMDGPU::TBUFFER_LOAD_FORMAT_X_BOTHEN_exact:
504 case AMDGPU::TBUFFER_LOAD_FORMAT_X_IDXEN:
505 case AMDGPU::TBUFFER_LOAD_FORMAT_X_IDXEN_exact:
506 case AMDGPU::TBUFFER_LOAD_FORMAT_X_OFFEN:
507 case AMDGPU::TBUFFER_LOAD_FORMAT_X_OFFEN_exact:
508 case AMDGPU::TBUFFER_LOAD_FORMAT_X_OFFSET:
509 case AMDGPU::TBUFFER_LOAD_FORMAT_X_OFFSET_exact:
510 case AMDGPU::TBUFFER_LOAD_FORMAT_X_VBUFFER_BOTHEN:
511 case AMDGPU::TBUFFER_LOAD_FORMAT_X_VBUFFER_BOTHEN_exact:
512 case AMDGPU::TBUFFER_LOAD_FORMAT_X_VBUFFER_IDXEN:
513 case AMDGPU::TBUFFER_LOAD_FORMAT_X_VBUFFER_IDXEN_exact:
514 case AMDGPU::TBUFFER_LOAD_FORMAT_X_VBUFFER_OFFEN:
515 case AMDGPU::TBUFFER_LOAD_FORMAT_X_VBUFFER_OFFEN_exact:
516 case AMDGPU::TBUFFER_LOAD_FORMAT_X_VBUFFER_OFFSET:
517 case AMDGPU::TBUFFER_LOAD_FORMAT_X_VBUFFER_OFFSET_exact:
518 return TBUFFER_LOAD;
519 case AMDGPU::TBUFFER_STORE_FORMAT_X_OFFEN:
520 case AMDGPU::TBUFFER_STORE_FORMAT_X_OFFEN_exact:
521 case AMDGPU::TBUFFER_STORE_FORMAT_X_OFFSET:
522 case AMDGPU::TBUFFER_STORE_FORMAT_X_OFFSET_exact:
523 case AMDGPU::TBUFFER_STORE_FORMAT_X_VBUFFER_OFFEN:
524 case AMDGPU::TBUFFER_STORE_FORMAT_X_VBUFFER_OFFEN_exact:
525 case AMDGPU::TBUFFER_STORE_FORMAT_X_VBUFFER_OFFSET:
526 case AMDGPU::TBUFFER_STORE_FORMAT_X_VBUFFER_OFFSET_exact:
527 return TBUFFER_STORE;
528 }
529 }
530 return UNKNOWN;
531 case AMDGPU::S_BUFFER_LOAD_DWORD_IMM:
532 case AMDGPU::S_BUFFER_LOAD_DWORDX2_IMM:
533 case AMDGPU::S_BUFFER_LOAD_DWORDX3_IMM:
534 case AMDGPU::S_BUFFER_LOAD_DWORDX4_IMM:
535 case AMDGPU::S_BUFFER_LOAD_DWORDX8_IMM:
536 case AMDGPU::S_BUFFER_LOAD_DWORDX2_IMM_ec:
537 case AMDGPU::S_BUFFER_LOAD_DWORDX3_IMM_ec:
538 case AMDGPU::S_BUFFER_LOAD_DWORDX4_IMM_ec:
539 case AMDGPU::S_BUFFER_LOAD_DWORDX8_IMM_ec:
540 return S_BUFFER_LOAD_IMM;
541 case AMDGPU::S_BUFFER_LOAD_DWORD_SGPR_IMM:
542 case AMDGPU::S_BUFFER_LOAD_DWORDX2_SGPR_IMM:
543 case AMDGPU::S_BUFFER_LOAD_DWORDX3_SGPR_IMM:
544 case AMDGPU::S_BUFFER_LOAD_DWORDX4_SGPR_IMM:
545 case AMDGPU::S_BUFFER_LOAD_DWORDX8_SGPR_IMM:
546 case AMDGPU::S_BUFFER_LOAD_DWORDX2_SGPR_IMM_ec:
547 case AMDGPU::S_BUFFER_LOAD_DWORDX3_SGPR_IMM_ec:
548 case AMDGPU::S_BUFFER_LOAD_DWORDX4_SGPR_IMM_ec:
549 case AMDGPU::S_BUFFER_LOAD_DWORDX8_SGPR_IMM_ec:
550 return S_BUFFER_LOAD_SGPR_IMM;
551 case AMDGPU::S_LOAD_DWORD_IMM:
552 case AMDGPU::S_LOAD_DWORDX2_IMM:
553 case AMDGPU::S_LOAD_DWORDX3_IMM:
554 case AMDGPU::S_LOAD_DWORDX4_IMM:
555 case AMDGPU::S_LOAD_DWORDX8_IMM:
556 case AMDGPU::S_LOAD_DWORDX2_IMM_ec:
557 case AMDGPU::S_LOAD_DWORDX3_IMM_ec:
558 case AMDGPU::S_LOAD_DWORDX4_IMM_ec:
559 case AMDGPU::S_LOAD_DWORDX8_IMM_ec:
560 return S_LOAD_IMM;
561 case AMDGPU::DS_READ_B32:
562 case AMDGPU::DS_READ_B32_gfx9:
563 case AMDGPU::DS_READ_B64:
564 case AMDGPU::DS_READ_B64_gfx9:
565 return DS_READ;
566 case AMDGPU::DS_WRITE_B32:
567 case AMDGPU::DS_WRITE_B32_gfx9:
568 case AMDGPU::DS_WRITE_B64:
569 case AMDGPU::DS_WRITE_B64_gfx9:
570 return DS_WRITE;
571 case AMDGPU::GLOBAL_LOAD_DWORD:
572 case AMDGPU::GLOBAL_LOAD_DWORDX2:
573 case AMDGPU::GLOBAL_LOAD_DWORDX3:
574 case AMDGPU::GLOBAL_LOAD_DWORDX4:
575 case AMDGPU::FLAT_LOAD_DWORD:
576 case AMDGPU::FLAT_LOAD_DWORDX2:
577 case AMDGPU::FLAT_LOAD_DWORDX3:
578 case AMDGPU::FLAT_LOAD_DWORDX4:
579 return FLAT_LOAD;
580 case AMDGPU::GLOBAL_LOAD_DWORD_SADDR:
581 case AMDGPU::GLOBAL_LOAD_DWORDX2_SADDR:
582 case AMDGPU::GLOBAL_LOAD_DWORDX3_SADDR:
583 case AMDGPU::GLOBAL_LOAD_DWORDX4_SADDR:
584 return GLOBAL_LOAD_SADDR;
585 case AMDGPU::GLOBAL_STORE_DWORD:
586 case AMDGPU::GLOBAL_STORE_DWORDX2:
587 case AMDGPU::GLOBAL_STORE_DWORDX3:
588 case AMDGPU::GLOBAL_STORE_DWORDX4:
589 case AMDGPU::FLAT_STORE_DWORD:
590 case AMDGPU::FLAT_STORE_DWORDX2:
591 case AMDGPU::FLAT_STORE_DWORDX3:
592 case AMDGPU::FLAT_STORE_DWORDX4:
593 return FLAT_STORE;
594 case AMDGPU::GLOBAL_STORE_DWORD_SADDR:
595 case AMDGPU::GLOBAL_STORE_DWORDX2_SADDR:
596 case AMDGPU::GLOBAL_STORE_DWORDX3_SADDR:
597 case AMDGPU::GLOBAL_STORE_DWORDX4_SADDR:
598 return GLOBAL_STORE_SADDR;
599 case AMDGPU::FLAT_LOAD_DWORD_SADDR:
600 case AMDGPU::FLAT_LOAD_DWORDX2_SADDR:
601 case AMDGPU::FLAT_LOAD_DWORDX3_SADDR:
602 case AMDGPU::FLAT_LOAD_DWORDX4_SADDR:
603 return FLAT_LOAD_SADDR;
604 case AMDGPU::FLAT_STORE_DWORD_SADDR:
605 case AMDGPU::FLAT_STORE_DWORDX2_SADDR:
606 case AMDGPU::FLAT_STORE_DWORDX3_SADDR:
607 case AMDGPU::FLAT_STORE_DWORDX4_SADDR:
608 return FLAT_STORE_SADDR;
609 }
610}
611
612/// Determines instruction subclass from opcode. Only instructions
613/// of the same subclass can be merged together. The merged instruction may have
614/// a different subclass but must have the same class.
615static unsigned getInstSubclass(unsigned Opc, const SIInstrInfo &TII) {
616 switch (Opc) {
617 default:
618 if (TII.isMUBUF(Opc))
620 if (TII.isImage(Opc)) {
622 assert(Info);
623 return Info->BaseOpcode;
624 }
625 if (TII.isMTBUF(Opc))
627 return -1;
628 case AMDGPU::DS_READ_B32:
629 case AMDGPU::DS_READ_B32_gfx9:
630 case AMDGPU::DS_READ_B64:
631 case AMDGPU::DS_READ_B64_gfx9:
632 case AMDGPU::DS_WRITE_B32:
633 case AMDGPU::DS_WRITE_B32_gfx9:
634 case AMDGPU::DS_WRITE_B64:
635 case AMDGPU::DS_WRITE_B64_gfx9:
636 return Opc;
637 case AMDGPU::S_BUFFER_LOAD_DWORD_IMM:
638 case AMDGPU::S_BUFFER_LOAD_DWORDX2_IMM:
639 case AMDGPU::S_BUFFER_LOAD_DWORDX3_IMM:
640 case AMDGPU::S_BUFFER_LOAD_DWORDX4_IMM:
641 case AMDGPU::S_BUFFER_LOAD_DWORDX8_IMM:
642 case AMDGPU::S_BUFFER_LOAD_DWORDX2_IMM_ec:
643 case AMDGPU::S_BUFFER_LOAD_DWORDX3_IMM_ec:
644 case AMDGPU::S_BUFFER_LOAD_DWORDX4_IMM_ec:
645 case AMDGPU::S_BUFFER_LOAD_DWORDX8_IMM_ec:
646 return AMDGPU::S_BUFFER_LOAD_DWORD_IMM;
647 case AMDGPU::S_BUFFER_LOAD_DWORD_SGPR_IMM:
648 case AMDGPU::S_BUFFER_LOAD_DWORDX2_SGPR_IMM:
649 case AMDGPU::S_BUFFER_LOAD_DWORDX3_SGPR_IMM:
650 case AMDGPU::S_BUFFER_LOAD_DWORDX4_SGPR_IMM:
651 case AMDGPU::S_BUFFER_LOAD_DWORDX8_SGPR_IMM:
652 case AMDGPU::S_BUFFER_LOAD_DWORDX2_SGPR_IMM_ec:
653 case AMDGPU::S_BUFFER_LOAD_DWORDX3_SGPR_IMM_ec:
654 case AMDGPU::S_BUFFER_LOAD_DWORDX4_SGPR_IMM_ec:
655 case AMDGPU::S_BUFFER_LOAD_DWORDX8_SGPR_IMM_ec:
656 return AMDGPU::S_BUFFER_LOAD_DWORD_SGPR_IMM;
657 case AMDGPU::S_LOAD_DWORD_IMM:
658 case AMDGPU::S_LOAD_DWORDX2_IMM:
659 case AMDGPU::S_LOAD_DWORDX3_IMM:
660 case AMDGPU::S_LOAD_DWORDX4_IMM:
661 case AMDGPU::S_LOAD_DWORDX8_IMM:
662 case AMDGPU::S_LOAD_DWORDX2_IMM_ec:
663 case AMDGPU::S_LOAD_DWORDX3_IMM_ec:
664 case AMDGPU::S_LOAD_DWORDX4_IMM_ec:
665 case AMDGPU::S_LOAD_DWORDX8_IMM_ec:
666 return AMDGPU::S_LOAD_DWORD_IMM;
667 case AMDGPU::GLOBAL_LOAD_DWORD:
668 case AMDGPU::GLOBAL_LOAD_DWORDX2:
669 case AMDGPU::GLOBAL_LOAD_DWORDX3:
670 case AMDGPU::GLOBAL_LOAD_DWORDX4:
671 case AMDGPU::FLAT_LOAD_DWORD:
672 case AMDGPU::FLAT_LOAD_DWORDX2:
673 case AMDGPU::FLAT_LOAD_DWORDX3:
674 case AMDGPU::FLAT_LOAD_DWORDX4:
675 return AMDGPU::FLAT_LOAD_DWORD;
676 case AMDGPU::GLOBAL_LOAD_DWORD_SADDR:
677 case AMDGPU::GLOBAL_LOAD_DWORDX2_SADDR:
678 case AMDGPU::GLOBAL_LOAD_DWORDX3_SADDR:
679 case AMDGPU::GLOBAL_LOAD_DWORDX4_SADDR:
680 return AMDGPU::GLOBAL_LOAD_DWORD_SADDR;
681 case AMDGPU::GLOBAL_STORE_DWORD:
682 case AMDGPU::GLOBAL_STORE_DWORDX2:
683 case AMDGPU::GLOBAL_STORE_DWORDX3:
684 case AMDGPU::GLOBAL_STORE_DWORDX4:
685 case AMDGPU::FLAT_STORE_DWORD:
686 case AMDGPU::FLAT_STORE_DWORDX2:
687 case AMDGPU::FLAT_STORE_DWORDX3:
688 case AMDGPU::FLAT_STORE_DWORDX4:
689 return AMDGPU::FLAT_STORE_DWORD;
690 case AMDGPU::GLOBAL_STORE_DWORD_SADDR:
691 case AMDGPU::GLOBAL_STORE_DWORDX2_SADDR:
692 case AMDGPU::GLOBAL_STORE_DWORDX3_SADDR:
693 case AMDGPU::GLOBAL_STORE_DWORDX4_SADDR:
694 return AMDGPU::GLOBAL_STORE_DWORD_SADDR;
695 case AMDGPU::FLAT_LOAD_DWORD_SADDR:
696 case AMDGPU::FLAT_LOAD_DWORDX2_SADDR:
697 case AMDGPU::FLAT_LOAD_DWORDX3_SADDR:
698 case AMDGPU::FLAT_LOAD_DWORDX4_SADDR:
699 return AMDGPU::FLAT_LOAD_DWORD_SADDR;
700 case AMDGPU::FLAT_STORE_DWORD_SADDR:
701 case AMDGPU::FLAT_STORE_DWORDX2_SADDR:
702 case AMDGPU::FLAT_STORE_DWORDX3_SADDR:
703 case AMDGPU::FLAT_STORE_DWORDX4_SADDR:
704 return AMDGPU::FLAT_STORE_DWORD_SADDR;
705 }
706}
707
708// GLOBAL loads and stores are classified as FLAT initially. If both combined
709// instructions are FLAT GLOBAL adjust the class to GLOBAL_LOAD or GLOBAL_STORE.
710// If either or both instructions are non segment specific FLAT the resulting
711// combined operation will be FLAT, potentially promoting one of the GLOBAL
712// operations to FLAT.
713// For other instructions return the original unmodified class.
714InstClassEnum
715SILoadStoreOptimizer::getCommonInstClass(const CombineInfo &CI,
716 const CombineInfo &Paired) {
717 assert(CI.InstClass == Paired.InstClass);
718
719 if ((CI.InstClass == FLAT_LOAD || CI.InstClass == FLAT_STORE) &&
721 return (CI.InstClass == FLAT_STORE) ? GLOBAL_STORE : GLOBAL_LOAD;
722
723 return CI.InstClass;
724}
725
726static AddressRegs getRegs(unsigned Opc, const SIInstrInfo &TII) {
727 AddressRegs Result;
728
729 if (TII.isMUBUF(Opc)) {
731 Result.VAddr = true;
733 Result.SRsrc = true;
735 Result.SOffset = true;
736
737 return Result;
738 }
739
740 if (TII.isImage(Opc)) {
741 int VAddr0Idx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::vaddr0);
742 if (VAddr0Idx >= 0) {
743 AMDGPU::OpName RsrcName =
744 TII.isMIMG(Opc) ? AMDGPU::OpName::srsrc : AMDGPU::OpName::rsrc;
745 int RsrcIdx = AMDGPU::getNamedOperandIdx(Opc, RsrcName);
746 Result.NumVAddrs = RsrcIdx - VAddr0Idx;
747 } else {
748 Result.VAddr = true;
749 }
750 Result.SRsrc = true;
752 if (Info && AMDGPU::getMIMGBaseOpcodeInfo(Info->BaseOpcode)->Sampler)
753 Result.SSamp = true;
754
755 return Result;
756 }
757 if (TII.isMTBUF(Opc)) {
759 Result.VAddr = true;
761 Result.SRsrc = true;
763 Result.SOffset = true;
764
765 return Result;
766 }
767
768 switch (Opc) {
769 default:
770 return Result;
771 case AMDGPU::S_BUFFER_LOAD_DWORD_SGPR_IMM:
772 case AMDGPU::S_BUFFER_LOAD_DWORDX2_SGPR_IMM:
773 case AMDGPU::S_BUFFER_LOAD_DWORDX3_SGPR_IMM:
774 case AMDGPU::S_BUFFER_LOAD_DWORDX4_SGPR_IMM:
775 case AMDGPU::S_BUFFER_LOAD_DWORDX8_SGPR_IMM:
776 case AMDGPU::S_BUFFER_LOAD_DWORDX2_SGPR_IMM_ec:
777 case AMDGPU::S_BUFFER_LOAD_DWORDX3_SGPR_IMM_ec:
778 case AMDGPU::S_BUFFER_LOAD_DWORDX4_SGPR_IMM_ec:
779 case AMDGPU::S_BUFFER_LOAD_DWORDX8_SGPR_IMM_ec:
780 Result.SOffset = true;
781 [[fallthrough]];
782 case AMDGPU::S_BUFFER_LOAD_DWORD_IMM:
783 case AMDGPU::S_BUFFER_LOAD_DWORDX2_IMM:
784 case AMDGPU::S_BUFFER_LOAD_DWORDX3_IMM:
785 case AMDGPU::S_BUFFER_LOAD_DWORDX4_IMM:
786 case AMDGPU::S_BUFFER_LOAD_DWORDX8_IMM:
787 case AMDGPU::S_BUFFER_LOAD_DWORDX2_IMM_ec:
788 case AMDGPU::S_BUFFER_LOAD_DWORDX3_IMM_ec:
789 case AMDGPU::S_BUFFER_LOAD_DWORDX4_IMM_ec:
790 case AMDGPU::S_BUFFER_LOAD_DWORDX8_IMM_ec:
791 case AMDGPU::S_LOAD_DWORD_IMM:
792 case AMDGPU::S_LOAD_DWORDX2_IMM:
793 case AMDGPU::S_LOAD_DWORDX3_IMM:
794 case AMDGPU::S_LOAD_DWORDX4_IMM:
795 case AMDGPU::S_LOAD_DWORDX8_IMM:
796 case AMDGPU::S_LOAD_DWORDX2_IMM_ec:
797 case AMDGPU::S_LOAD_DWORDX3_IMM_ec:
798 case AMDGPU::S_LOAD_DWORDX4_IMM_ec:
799 case AMDGPU::S_LOAD_DWORDX8_IMM_ec:
800 Result.SBase = true;
801 return Result;
802 case AMDGPU::DS_READ_B32:
803 case AMDGPU::DS_READ_B64:
804 case AMDGPU::DS_READ_B32_gfx9:
805 case AMDGPU::DS_READ_B64_gfx9:
806 case AMDGPU::DS_WRITE_B32:
807 case AMDGPU::DS_WRITE_B64:
808 case AMDGPU::DS_WRITE_B32_gfx9:
809 case AMDGPU::DS_WRITE_B64_gfx9:
810 Result.Addr = true;
811 return Result;
812 case AMDGPU::GLOBAL_LOAD_DWORD_SADDR:
813 case AMDGPU::GLOBAL_LOAD_DWORDX2_SADDR:
814 case AMDGPU::GLOBAL_LOAD_DWORDX3_SADDR:
815 case AMDGPU::GLOBAL_LOAD_DWORDX4_SADDR:
816 case AMDGPU::GLOBAL_STORE_DWORD_SADDR:
817 case AMDGPU::GLOBAL_STORE_DWORDX2_SADDR:
818 case AMDGPU::GLOBAL_STORE_DWORDX3_SADDR:
819 case AMDGPU::GLOBAL_STORE_DWORDX4_SADDR:
820 case AMDGPU::FLAT_LOAD_DWORD_SADDR:
821 case AMDGPU::FLAT_LOAD_DWORDX2_SADDR:
822 case AMDGPU::FLAT_LOAD_DWORDX3_SADDR:
823 case AMDGPU::FLAT_LOAD_DWORDX4_SADDR:
824 case AMDGPU::FLAT_STORE_DWORD_SADDR:
825 case AMDGPU::FLAT_STORE_DWORDX2_SADDR:
826 case AMDGPU::FLAT_STORE_DWORDX3_SADDR:
827 case AMDGPU::FLAT_STORE_DWORDX4_SADDR:
828 Result.SAddr = true;
829 [[fallthrough]];
830 case AMDGPU::GLOBAL_LOAD_DWORD:
831 case AMDGPU::GLOBAL_LOAD_DWORDX2:
832 case AMDGPU::GLOBAL_LOAD_DWORDX3:
833 case AMDGPU::GLOBAL_LOAD_DWORDX4:
834 case AMDGPU::GLOBAL_STORE_DWORD:
835 case AMDGPU::GLOBAL_STORE_DWORDX2:
836 case AMDGPU::GLOBAL_STORE_DWORDX3:
837 case AMDGPU::GLOBAL_STORE_DWORDX4:
838 case AMDGPU::FLAT_LOAD_DWORD:
839 case AMDGPU::FLAT_LOAD_DWORDX2:
840 case AMDGPU::FLAT_LOAD_DWORDX3:
841 case AMDGPU::FLAT_LOAD_DWORDX4:
842 case AMDGPU::FLAT_STORE_DWORD:
843 case AMDGPU::FLAT_STORE_DWORDX2:
844 case AMDGPU::FLAT_STORE_DWORDX3:
845 case AMDGPU::FLAT_STORE_DWORDX4:
846 Result.VAddr = true;
847 return Result;
848 }
849}
850
851void SILoadStoreOptimizer::CombineInfo::setMI(MachineBasicBlock::iterator MI,
852 const SILoadStoreOptimizer &LSO) {
853 I = MI;
854 unsigned Opc = MI->getOpcode();
855 InstClass = getInstClass(Opc, *LSO.TII);
856
857 if (InstClass == UNKNOWN)
858 return;
859
860 DataRC = LSO.getDataRegClass(*MI);
861
862 switch (InstClass) {
863 case DS_READ:
864 EltSize =
865 (Opc == AMDGPU::DS_READ_B64 || Opc == AMDGPU::DS_READ_B64_gfx9) ? 8
866 : 4;
867 break;
868 case DS_WRITE:
869 EltSize =
870 (Opc == AMDGPU::DS_WRITE_B64 || Opc == AMDGPU::DS_WRITE_B64_gfx9) ? 8
871 : 4;
872 break;
873 case S_BUFFER_LOAD_IMM:
874 case S_BUFFER_LOAD_SGPR_IMM:
875 case S_LOAD_IMM:
876 EltSize = AMDGPU::convertSMRDOffsetUnits(*LSO.STM, 4);
877 break;
878 default:
879 EltSize = 4;
880 break;
881 }
882
883 if (InstClass == MIMG) {
884 DMask = LSO.TII->getNamedOperand(*I, AMDGPU::OpName::dmask)->getImm();
885 // Offset is not considered for MIMG instructions.
886 Offset = 0;
887 } else {
888 int OffsetIdx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::offset);
889 Offset = I->getOperand(OffsetIdx).getImm();
890 }
891
892 if (InstClass == TBUFFER_LOAD || InstClass == TBUFFER_STORE) {
893 Format = LSO.TII->getNamedOperand(*I, AMDGPU::OpName::format)->getImm();
894 const AMDGPU::GcnBufferFormatInfo *Info =
895 AMDGPU::getGcnBufferFormatInfo(Format, *LSO.STM);
896 EltSize = Info->BitsPerComp / 8;
897 }
898
899 Width = getOpcodeWidth(*I, *LSO.TII);
900
901 if ((InstClass == DS_READ) || (InstClass == DS_WRITE)) {
902 Offset &= 0xffff;
903 } else if (InstClass != MIMG) {
904 CPol = LSO.TII->getNamedOperand(*I, AMDGPU::OpName::cpol)->getImm();
905 }
906
907 AddressRegs Regs = getRegs(Opc, *LSO.TII);
908 bool isVIMAGEorVSAMPLE = LSO.TII->isVIMAGE(*I) || LSO.TII->isVSAMPLE(*I);
909
910 NumAddresses = 0;
911 for (unsigned J = 0; J < Regs.NumVAddrs; J++)
912 AddrIdx[NumAddresses++] =
913 AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::vaddr0) + J;
914 if (Regs.Addr)
915 AddrIdx[NumAddresses++] =
916 AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::addr);
917 if (Regs.SBase)
918 AddrIdx[NumAddresses++] =
919 AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::sbase);
920 if (Regs.SRsrc)
921 AddrIdx[NumAddresses++] = AMDGPU::getNamedOperandIdx(
922 Opc, isVIMAGEorVSAMPLE ? AMDGPU::OpName::rsrc : AMDGPU::OpName::srsrc);
923 if (Regs.SOffset)
924 AddrIdx[NumAddresses++] =
925 AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::soffset);
926 if (Regs.SAddr)
927 AddrIdx[NumAddresses++] =
928 AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::saddr);
929 if (Regs.VAddr)
930 AddrIdx[NumAddresses++] =
931 AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::vaddr);
932 if (Regs.SSamp)
933 AddrIdx[NumAddresses++] = AMDGPU::getNamedOperandIdx(
934 Opc, isVIMAGEorVSAMPLE ? AMDGPU::OpName::samp : AMDGPU::OpName::ssamp);
935 assert(NumAddresses <= MaxAddressRegs);
936
937 for (unsigned J = 0; J < NumAddresses; J++)
938 AddrReg[J] = &I->getOperand(AddrIdx[J]);
939}
940
941} // end anonymous namespace.
942
943INITIALIZE_PASS_BEGIN(SILoadStoreOptimizerLegacy, DEBUG_TYPE,
944 "SI Load Store Optimizer", false, false)
946INITIALIZE_PASS_END(SILoadStoreOptimizerLegacy, DEBUG_TYPE,
947 "SI Load Store Optimizer", false, false)
948
949char SILoadStoreOptimizerLegacy::ID = 0;
950
951char &llvm::SILoadStoreOptimizerLegacyID = SILoadStoreOptimizerLegacy::ID;
952
954 return new SILoadStoreOptimizerLegacy();
955}
956
958 DenseSet<Register> &RegDefs,
959 DenseSet<Register> &RegUses) {
960 for (const auto &Op : MI.operands()) {
961 if (!Op.isReg())
962 continue;
963 if (Op.isDef())
964 RegDefs.insert(Op.getReg());
965 if (Op.readsReg())
966 RegUses.insert(Op.getReg());
967 }
968}
969
970bool SILoadStoreOptimizer::canSwapInstructions(
971 const DenseSet<Register> &ARegDefs, const DenseSet<Register> &ARegUses,
972 const MachineInstr &A, const MachineInstr &B) const {
973 if (A.mayLoadOrStore() && B.mayLoadOrStore() &&
974 (A.mayStore() || B.mayStore()) && A.mayAlias(AA, B, true))
975 return false;
976 for (const auto &BOp : B.operands()) {
977 if (!BOp.isReg())
978 continue;
979 if ((BOp.isDef() || BOp.readsReg()) && ARegDefs.contains(BOp.getReg()))
980 return false;
981 if (BOp.isDef() && ARegUses.contains(BOp.getReg()))
982 return false;
983 }
984 return true;
985}
986
987// Given that \p CI and \p Paired are adjacent memory operations produce a new
988// MMO for the combined operation with a new access size.
989MachineMemOperand *
990SILoadStoreOptimizer::combineKnownAdjacentMMOs(const CombineInfo &CI,
991 const CombineInfo &Paired) {
992 const MachineMemOperand *MMOa = *CI.I->memoperands_begin();
993 const MachineMemOperand *MMOb = *Paired.I->memoperands_begin();
994
995 unsigned Size = MMOa->getSize().getValue() + MMOb->getSize().getValue();
996
997 // A base pointer for the combined operation is the same as the leading
998 // operation's pointer.
999 if (Paired < CI)
1000 std::swap(MMOa, MMOb);
1001
1002 MachinePointerInfo PtrInfo(MMOa->getPointerInfo());
1003 // If merging FLAT and GLOBAL set address space to FLAT.
1004 if (MMOb->getAddrSpace() == AMDGPUAS::FLAT_ADDRESS)
1005 PtrInfo.AddrSpace = AMDGPUAS::FLAT_ADDRESS;
1006
1007 MachineFunction *MF = CI.I->getMF();
1008 return MF->getMachineMemOperand(MMOa, PtrInfo, Size);
1009}
1010
1011bool SILoadStoreOptimizer::dmasksCanBeCombined(const CombineInfo &CI,
1012 const SIInstrInfo &TII,
1013 const CombineInfo &Paired) {
1014 assert(CI.InstClass == MIMG);
1015
1016 // Ignore instructions with tfe/lwe set.
1017 const auto *TFEOp = TII.getNamedOperand(*CI.I, AMDGPU::OpName::tfe);
1018 const auto *LWEOp = TII.getNamedOperand(*CI.I, AMDGPU::OpName::lwe);
1019
1020 if ((TFEOp && TFEOp->getImm()) || (LWEOp && LWEOp->getImm()))
1021 return false;
1022
1023 // Check other optional immediate operands for equality.
1024 AMDGPU::OpName OperandsToMatch[] = {
1025 AMDGPU::OpName::cpol, AMDGPU::OpName::d16, AMDGPU::OpName::unorm,
1026 AMDGPU::OpName::da, AMDGPU::OpName::r128, AMDGPU::OpName::a16};
1027
1028 for (AMDGPU::OpName op : OperandsToMatch) {
1029 int Idx = AMDGPU::getNamedOperandIdx(CI.I->getOpcode(), op);
1030 if (AMDGPU::getNamedOperandIdx(Paired.I->getOpcode(), op) != Idx)
1031 return false;
1032 if (Idx != -1 &&
1033 CI.I->getOperand(Idx).getImm() != Paired.I->getOperand(Idx).getImm())
1034 return false;
1035 }
1036
1037 // Check DMask for overlaps.
1038 unsigned MaxMask = std::max(CI.DMask, Paired.DMask);
1039 unsigned MinMask = std::min(CI.DMask, Paired.DMask);
1040
1041 if (!MaxMask)
1042 return false;
1043
1044 unsigned AllowedBitsForMin = llvm::countr_zero(MaxMask);
1045 if ((1u << AllowedBitsForMin) <= MinMask)
1046 return false;
1047
1048 return true;
1049}
1050
1051static unsigned getBufferFormatWithCompCount(unsigned OldFormat,
1052 unsigned ComponentCount,
1053 const GCNSubtarget &STI) {
1054 if (ComponentCount > 4)
1055 return 0;
1056
1057 const llvm::AMDGPU::GcnBufferFormatInfo *OldFormatInfo =
1059 if (!OldFormatInfo)
1060 return 0;
1061
1062 const llvm::AMDGPU::GcnBufferFormatInfo *NewFormatInfo =
1064 ComponentCount,
1065 OldFormatInfo->NumFormat, STI);
1066
1067 if (!NewFormatInfo)
1068 return 0;
1069
1070 assert(NewFormatInfo->NumFormat == OldFormatInfo->NumFormat &&
1071 NewFormatInfo->BitsPerComp == OldFormatInfo->BitsPerComp);
1072
1073 return NewFormatInfo->Format;
1074}
1075
1076// Return the value in the inclusive range [Lo,Hi] that is aligned to the
1077// highest power of two. Note that the result is well defined for all inputs
1078// including corner cases like:
1079// - if Lo == Hi, return that value
1080// - if Lo == 0, return 0 (even though the "- 1" below underflows
1081// - if Lo > Hi, return 0 (as if the range wrapped around)
1085
1086bool SILoadStoreOptimizer::offsetsCanBeCombined(CombineInfo &CI,
1087 const GCNSubtarget &STI,
1088 CombineInfo &Paired,
1089 bool Modify) {
1090 assert(CI.InstClass != MIMG);
1091
1092 // XXX - Would the same offset be OK? Is there any reason this would happen or
1093 // be useful?
1094 if (CI.Offset == Paired.Offset)
1095 return false;
1096
1097 // This won't be valid if the offset isn't aligned.
1098 if ((CI.Offset % CI.EltSize != 0) || (Paired.Offset % CI.EltSize != 0))
1099 return false;
1100
1101 if (CI.InstClass == TBUFFER_LOAD || CI.InstClass == TBUFFER_STORE) {
1102
1103 const llvm::AMDGPU::GcnBufferFormatInfo *Info0 =
1105 const llvm::AMDGPU::GcnBufferFormatInfo *Info1 =
1106 llvm::AMDGPU::getGcnBufferFormatInfo(Paired.Format, STI);
1107
1108 if (Info0->BitsPerComp != Info1->BitsPerComp ||
1109 Info0->NumFormat != Info1->NumFormat)
1110 return false;
1111
1112 // For 8-bit or 16-bit formats there is no 3-component variant.
1113 // If NumCombinedComponents is 3, try the 4-component format and use XYZ.
1114 // Example:
1115 // tbuffer_load_format_x + tbuffer_load_format_x + tbuffer_load_format_x
1116 // ==> tbuffer_load_format_xyz with format:[BUF_FMT_16_16_16_16_SNORM]
1117 unsigned NumCombinedComponents = CI.Width + Paired.Width;
1118 if (NumCombinedComponents == 3 && CI.EltSize <= 2)
1119 NumCombinedComponents = 4;
1120
1121 if (getBufferFormatWithCompCount(CI.Format, NumCombinedComponents, STI) ==
1122 0)
1123 return false;
1124
1125 // Merge only when the two access ranges are strictly back-to-back,
1126 // any gap or overlap can over-write data or leave holes.
1127 unsigned ElemIndex0 = CI.Offset / CI.EltSize;
1128 unsigned ElemIndex1 = Paired.Offset / Paired.EltSize;
1129 if (ElemIndex0 + CI.Width != ElemIndex1 &&
1130 ElemIndex1 + Paired.Width != ElemIndex0)
1131 return false;
1132
1133 // 1-byte formats require 1-byte alignment.
1134 // 2-byte formats require 2-byte alignment.
1135 // 4-byte and larger formats require 4-byte alignment.
1136 unsigned MergedBytes = CI.EltSize * NumCombinedComponents;
1137 unsigned RequiredAlign = std::min(MergedBytes, 4u);
1138 unsigned MinOff = std::min(CI.Offset, Paired.Offset);
1139 if (MinOff % RequiredAlign != 0)
1140 return false;
1141
1142 return true;
1143 }
1144
1145 uint32_t EltOffset0 = CI.Offset / CI.EltSize;
1146 uint32_t EltOffset1 = Paired.Offset / CI.EltSize;
1147 CI.UseST64 = false;
1148 CI.BaseOff = 0;
1149
1150 // Handle all non-DS instructions.
1151 if ((CI.InstClass != DS_READ) && (CI.InstClass != DS_WRITE)) {
1152 if (EltOffset0 + CI.Width != EltOffset1 &&
1153 EltOffset1 + Paired.Width != EltOffset0)
1154 return false;
1155 // Instructions with scale_offset modifier cannot be combined unless we
1156 // also generate a code to scale the offset and reset that bit.
1157 if (CI.CPol != Paired.CPol || (CI.CPol & AMDGPU::CPol::SCAL))
1158 return false;
1159 if (CI.InstClass == S_LOAD_IMM || CI.InstClass == S_BUFFER_LOAD_IMM ||
1160 CI.InstClass == S_BUFFER_LOAD_SGPR_IMM) {
1161 // Reject cases like:
1162 // dword + dwordx2 -> dwordx3
1163 // dword + dwordx3 -> dwordx4
1164 // If we tried to combine these cases, we would fail to extract a subreg
1165 // for the result of the second load due to SGPR alignment requirements.
1166 if (CI.Width != Paired.Width &&
1167 (CI.Width < Paired.Width) == (CI.Offset < Paired.Offset))
1168 return false;
1169 }
1170 return true;
1171 }
1172
1173 // If the offset in elements doesn't fit in 8-bits, we might be able to use
1174 // the stride 64 versions.
1175 if ((EltOffset0 % 64 == 0) && (EltOffset1 % 64) == 0 &&
1176 isUInt<8>(EltOffset0 / 64) && isUInt<8>(EltOffset1 / 64)) {
1177 if (Modify) {
1178 CI.Offset = EltOffset0 / 64;
1179 Paired.Offset = EltOffset1 / 64;
1180 CI.UseST64 = true;
1181 }
1182 return true;
1183 }
1184
1185 // Check if the new offsets fit in the reduced 8-bit range.
1186 if (isUInt<8>(EltOffset0) && isUInt<8>(EltOffset1)) {
1187 if (Modify) {
1188 CI.Offset = EltOffset0;
1189 Paired.Offset = EltOffset1;
1190 }
1191 return true;
1192 }
1193
1194 // Try to shift base address to decrease offsets.
1195 uint32_t Min = std::min(EltOffset0, EltOffset1);
1196 uint32_t Max = std::max(EltOffset0, EltOffset1);
1197
1198 const uint32_t Mask = maskTrailingOnes<uint32_t>(8) * 64;
1199 if (((Max - Min) & ~Mask) == 0) {
1200 if (Modify) {
1201 // From the range of values we could use for BaseOff, choose the one that
1202 // is aligned to the highest power of two, to maximise the chance that
1203 // the same offset can be reused for other load/store pairs.
1204 uint32_t BaseOff = mostAlignedValueInRange(Max - 0xff * 64, Min);
1205 // Copy the low bits of the offsets, so that when we adjust them by
1206 // subtracting BaseOff they will be multiples of 64.
1207 BaseOff |= Min & maskTrailingOnes<uint32_t>(6);
1208 CI.BaseOff = BaseOff * CI.EltSize;
1209 CI.Offset = (EltOffset0 - BaseOff) / 64;
1210 Paired.Offset = (EltOffset1 - BaseOff) / 64;
1211 CI.UseST64 = true;
1212 }
1213 return true;
1214 }
1215
1216 if (isUInt<8>(Max - Min)) {
1217 if (Modify) {
1218 // From the range of values we could use for BaseOff, choose the one that
1219 // is aligned to the highest power of two, to maximise the chance that
1220 // the same offset can be reused for other load/store pairs.
1221 uint32_t BaseOff = mostAlignedValueInRange(Max - 0xff, Min);
1222 CI.BaseOff = BaseOff * CI.EltSize;
1223 CI.Offset = EltOffset0 - BaseOff;
1224 Paired.Offset = EltOffset1 - BaseOff;
1225 }
1226 return true;
1227 }
1228
1229 return false;
1230}
1231
1232bool SILoadStoreOptimizer::widthsFit(const GCNSubtarget &STM,
1233 const CombineInfo &CI,
1234 const CombineInfo &Paired) {
1235 const unsigned Width = (CI.Width + Paired.Width);
1236 switch (CI.InstClass) {
1237 default:
1238 return (Width <= 4) && (STM.hasDwordx3LoadStores() || (Width != 3));
1239 case S_BUFFER_LOAD_IMM:
1240 case S_BUFFER_LOAD_SGPR_IMM:
1241 case S_LOAD_IMM:
1242 switch (Width) {
1243 default:
1244 return false;
1245 case 2:
1246 case 4:
1247 case 8:
1248 return true;
1249 case 3:
1250 return STM.hasScalarDwordx3Loads();
1251 }
1252 }
1253}
1254
1255const TargetRegisterClass *
1256SILoadStoreOptimizer::getDataRegClass(const MachineInstr &MI) const {
1257 if (const auto *Dst = TII->getNamedOperand(MI, AMDGPU::OpName::vdst)) {
1258 return TRI->getRegClassForReg(*MRI, Dst->getReg());
1259 }
1260 if (const auto *Src = TII->getNamedOperand(MI, AMDGPU::OpName::vdata)) {
1261 return TRI->getRegClassForReg(*MRI, Src->getReg());
1262 }
1263 if (const auto *Src = TII->getNamedOperand(MI, AMDGPU::OpName::data0)) {
1264 return TRI->getRegClassForReg(*MRI, Src->getReg());
1265 }
1266 if (const auto *Dst = TII->getNamedOperand(MI, AMDGPU::OpName::sdst)) {
1267 return TRI->getRegClassForReg(*MRI, Dst->getReg());
1268 }
1269 if (const auto *Src = TII->getNamedOperand(MI, AMDGPU::OpName::sdata)) {
1270 return TRI->getRegClassForReg(*MRI, Src->getReg());
1271 }
1272 return nullptr;
1273}
1274
1275/// This function assumes that CI comes before Paired in a basic block. Return
1276/// an insertion point for the merged instruction or nullptr on failure.
1277SILoadStoreOptimizer::CombineInfo *
1278SILoadStoreOptimizer::checkAndPrepareMerge(CombineInfo &CI,
1279 CombineInfo &Paired) {
1280 // If another instruction has already been merged into CI, it may now be a
1281 // type that we can't do any further merging into.
1282 if (CI.InstClass == UNKNOWN || Paired.InstClass == UNKNOWN)
1283 return nullptr;
1284 assert(CI.InstClass == Paired.InstClass);
1285
1286 if (getInstSubclass(CI.I->getOpcode(), *TII) !=
1287 getInstSubclass(Paired.I->getOpcode(), *TII))
1288 return nullptr;
1289
1290 // Check both offsets (or masks for MIMG) can be combined and fit in the
1291 // reduced range.
1292 if (CI.InstClass == MIMG) {
1293 if (!dmasksCanBeCombined(CI, *TII, Paired))
1294 return nullptr;
1295 } else {
1296 if (!widthsFit(*STM, CI, Paired) || !offsetsCanBeCombined(CI, *STM, Paired))
1297 return nullptr;
1298 }
1299
1300 DenseSet<Register> RegDefs;
1301 DenseSet<Register> RegUses;
1302 CombineInfo *Where;
1303 if (CI.I->mayLoad()) {
1304 // Try to hoist Paired up to CI.
1305 addDefsUsesToList(*Paired.I, RegDefs, RegUses);
1306 for (MachineBasicBlock::iterator MBBI = Paired.I; --MBBI != CI.I;) {
1307 if (!canSwapInstructions(RegDefs, RegUses, *Paired.I, *MBBI))
1308 return nullptr;
1309 }
1310 Where = &CI;
1311 } else {
1312 // Try to sink CI down to Paired.
1313 addDefsUsesToList(*CI.I, RegDefs, RegUses);
1314 for (MachineBasicBlock::iterator MBBI = CI.I; ++MBBI != Paired.I;) {
1315 if (!canSwapInstructions(RegDefs, RegUses, *CI.I, *MBBI))
1316 return nullptr;
1317 }
1318 Where = &Paired;
1319 }
1320
1321 // Call offsetsCanBeCombined with modify = true so that the offsets are
1322 // correct for the new instruction. This should return true, because
1323 // this function should only be called on CombineInfo objects that
1324 // have already been confirmed to be mergeable.
1325 if (CI.InstClass == DS_READ || CI.InstClass == DS_WRITE)
1326 offsetsCanBeCombined(CI, *STM, Paired, true);
1327
1328 if (CI.InstClass == DS_WRITE) {
1329 // Both data operands must be AGPR or VGPR, so the data registers needs to
1330 // be constrained to one or the other. We expect to only emit the VGPR form
1331 // here for now.
1332 //
1333 // FIXME: There is currently a hack in getRegClass to report that the write2
1334 // operands are VGPRs. In the future we should have separate agpr
1335 // instruction definitions.
1336 const MachineOperand *Data0 =
1337 TII->getNamedOperand(*CI.I, AMDGPU::OpName::data0);
1338 const MachineOperand *Data1 =
1339 TII->getNamedOperand(*Paired.I, AMDGPU::OpName::data0);
1340
1341 const MCInstrDesc &Write2Opc = TII->get(getWrite2Opcode(CI));
1342 int Data0Idx = AMDGPU::getNamedOperandIdx(Write2Opc.getOpcode(),
1343 AMDGPU::OpName::data0);
1344 int Data1Idx = AMDGPU::getNamedOperandIdx(Write2Opc.getOpcode(),
1345 AMDGPU::OpName::data1);
1346
1347 const TargetRegisterClass *DataRC0 = TII->getRegClass(Write2Opc, Data0Idx);
1348
1349 const TargetRegisterClass *DataRC1 = TII->getRegClass(Write2Opc, Data1Idx);
1350
1351 if (unsigned SubReg = Data0->getSubReg()) {
1352 DataRC0 = TRI->getMatchingSuperRegClass(MRI->getRegClass(Data0->getReg()),
1353 DataRC0, SubReg);
1354 }
1355
1356 if (unsigned SubReg = Data1->getSubReg()) {
1357 DataRC1 = TRI->getMatchingSuperRegClass(MRI->getRegClass(Data1->getReg()),
1358 DataRC1, SubReg);
1359 }
1360
1361 if (!MRI->constrainRegClass(Data0->getReg(), DataRC0) ||
1362 !MRI->constrainRegClass(Data1->getReg(), DataRC1))
1363 return nullptr;
1364
1365 // TODO: If one register can be constrained, and not the other, insert a
1366 // copy.
1367 }
1368
1369 return Where;
1370}
1371
1372// Copy the merged load result from DestReg to the original dest regs of CI and
1373// Paired.
1374void SILoadStoreOptimizer::copyToDestRegs(
1375 CombineInfo &CI, CombineInfo &Paired,
1376 MachineBasicBlock::iterator InsertBefore, const DebugLoc &DL,
1377 AMDGPU::OpName OpName, Register DestReg) const {
1378 MachineBasicBlock *MBB = CI.I->getParent();
1379
1380 auto [SubRegIdx0, SubRegIdx1] = getSubRegIdxs(CI, Paired);
1381
1382 // Copy to the old destination registers.
1383 const MCInstrDesc &CopyDesc = TII->get(TargetOpcode::COPY);
1384 auto *Dest0 = TII->getNamedOperand(*CI.I, OpName);
1385 auto *Dest1 = TII->getNamedOperand(*Paired.I, OpName);
1386
1387 // The constrained sload instructions in S_LOAD_IMM class will have
1388 // `early-clobber` flag in the dst operand. Remove the flag before using the
1389 // MOs in copies.
1390 Dest0->setIsEarlyClobber(false);
1391 Dest1->setIsEarlyClobber(false);
1392
1393 BuildMI(*MBB, InsertBefore, DL, CopyDesc)
1394 .add(*Dest0) // Copy to same destination including flags and sub reg.
1395 .addReg(DestReg, {}, SubRegIdx0);
1396 BuildMI(*MBB, InsertBefore, DL, CopyDesc)
1397 .add(*Dest1)
1398 .addReg(DestReg, RegState::Kill, SubRegIdx1);
1399}
1400
1401// Return a register for the source of the merged store after copying the
1402// original source regs of CI and Paired into it.
1404SILoadStoreOptimizer::copyFromSrcRegs(CombineInfo &CI, CombineInfo &Paired,
1405 MachineBasicBlock::iterator InsertBefore,
1406 const DebugLoc &DL,
1407 AMDGPU::OpName OpName) const {
1408 MachineBasicBlock *MBB = CI.I->getParent();
1409
1410 auto [SubRegIdx0, SubRegIdx1] = getSubRegIdxs(CI, Paired);
1411
1412 // Copy to the new source register.
1413 const TargetRegisterClass *SuperRC = getTargetRegisterClass(CI, Paired);
1414 Register SrcReg = MRI->createVirtualRegister(SuperRC);
1415
1416 const auto *Src0 = TII->getNamedOperand(*CI.I, OpName);
1417 const auto *Src1 = TII->getNamedOperand(*Paired.I, OpName);
1418
1419 BuildMI(*MBB, InsertBefore, DL, TII->get(AMDGPU::REG_SEQUENCE), SrcReg)
1420 .add(*Src0)
1421 .addImm(SubRegIdx0)
1422 .add(*Src1)
1423 .addImm(SubRegIdx1);
1424
1425 return SrcReg;
1426}
1427
1428unsigned SILoadStoreOptimizer::read2Opcode(unsigned EltSize) const {
1429 if (STM->ldsRequiresM0Init())
1430 return (EltSize == 4) ? AMDGPU::DS_READ2_B32 : AMDGPU::DS_READ2_B64;
1431 return (EltSize == 4) ? AMDGPU::DS_READ2_B32_gfx9 : AMDGPU::DS_READ2_B64_gfx9;
1432}
1433
1434unsigned SILoadStoreOptimizer::read2ST64Opcode(unsigned EltSize) const {
1435 if (STM->ldsRequiresM0Init())
1436 return (EltSize == 4) ? AMDGPU::DS_READ2ST64_B32 : AMDGPU::DS_READ2ST64_B64;
1437
1438 return (EltSize == 4) ? AMDGPU::DS_READ2ST64_B32_gfx9
1439 : AMDGPU::DS_READ2ST64_B64_gfx9;
1440}
1441
1443SILoadStoreOptimizer::mergeRead2Pair(CombineInfo &CI, CombineInfo &Paired,
1444 MachineBasicBlock::iterator InsertBefore) {
1445 MachineBasicBlock *MBB = CI.I->getParent();
1446
1447 // Be careful, since the addresses could be subregisters themselves in weird
1448 // cases, like vectors of pointers.
1449 const auto *AddrReg = TII->getNamedOperand(*CI.I, AMDGPU::OpName::addr);
1450
1451 unsigned NewOffset0 = std::min(CI.Offset, Paired.Offset);
1452 unsigned NewOffset1 = std::max(CI.Offset, Paired.Offset);
1453 unsigned Opc =
1454 CI.UseST64 ? read2ST64Opcode(CI.EltSize) : read2Opcode(CI.EltSize);
1455
1456 assert((isUInt<8>(NewOffset0) && isUInt<8>(NewOffset1)) &&
1457 (NewOffset0 != NewOffset1) && "Computed offset doesn't fit");
1458
1459 const MCInstrDesc &Read2Desc = TII->get(Opc);
1460
1461 const TargetRegisterClass *SuperRC = getTargetRegisterClass(CI, Paired);
1462 Register DestReg = MRI->createVirtualRegister(SuperRC);
1463
1464 DebugLoc DL =
1465 DebugLoc::getMergedLocation(CI.I->getDebugLoc(), Paired.I->getDebugLoc());
1466
1467 Register BaseReg = AddrReg->getReg();
1468 unsigned BaseSubReg = AddrReg->getSubReg();
1469 RegState BaseRegFlags = {};
1470 if (CI.BaseOff) {
1471 Register ImmReg = MRI->createVirtualRegister(&AMDGPU::SReg_32RegClass);
1472 BuildMI(*MBB, InsertBefore, DL, TII->get(AMDGPU::S_MOV_B32), ImmReg)
1473 .addImm(CI.BaseOff);
1474
1475 BaseReg = MRI->createVirtualRegister(&AMDGPU::VGPR_32RegClass);
1476 BaseRegFlags = RegState::Kill;
1477
1478 TII->getAddNoCarry(*MBB, InsertBefore, DL, BaseReg)
1479 .addReg(ImmReg)
1480 .addReg(AddrReg->getReg(), {}, BaseSubReg)
1481 .addImm(0); // clamp bit
1482 BaseSubReg = 0;
1483 }
1484
1485 MachineInstrBuilder Read2 =
1486 BuildMI(*MBB, InsertBefore, DL, Read2Desc, DestReg)
1487 .addReg(BaseReg, BaseRegFlags, BaseSubReg) // addr
1488 .addImm(NewOffset0) // offset0
1489 .addImm(NewOffset1) // offset1
1490 .addImm(0) // gds
1491 .cloneMergedMemRefs({&*CI.I, &*Paired.I});
1492
1493 copyToDestRegs(CI, Paired, InsertBefore, DL, AMDGPU::OpName::vdst, DestReg);
1494
1495 CI.I->eraseFromParent();
1496 Paired.I->eraseFromParent();
1497
1498 LLVM_DEBUG(dbgs() << "Inserted read2: " << *Read2 << '\n');
1499 return Read2;
1500}
1501
1502unsigned SILoadStoreOptimizer::write2Opcode(unsigned EltSize) const {
1503 if (STM->ldsRequiresM0Init())
1504 return (EltSize == 4) ? AMDGPU::DS_WRITE2_B32 : AMDGPU::DS_WRITE2_B64;
1505 return (EltSize == 4) ? AMDGPU::DS_WRITE2_B32_gfx9
1506 : AMDGPU::DS_WRITE2_B64_gfx9;
1507}
1508
1509unsigned SILoadStoreOptimizer::write2ST64Opcode(unsigned EltSize) const {
1510 if (STM->ldsRequiresM0Init())
1511 return (EltSize == 4) ? AMDGPU::DS_WRITE2ST64_B32
1512 : AMDGPU::DS_WRITE2ST64_B64;
1513
1514 return (EltSize == 4) ? AMDGPU::DS_WRITE2ST64_B32_gfx9
1515 : AMDGPU::DS_WRITE2ST64_B64_gfx9;
1516}
1517
1518unsigned SILoadStoreOptimizer::getWrite2Opcode(const CombineInfo &CI) const {
1519 return CI.UseST64 ? write2ST64Opcode(CI.EltSize) : write2Opcode(CI.EltSize);
1520}
1521
1522MachineBasicBlock::iterator SILoadStoreOptimizer::mergeWrite2Pair(
1523 CombineInfo &CI, CombineInfo &Paired,
1524 MachineBasicBlock::iterator InsertBefore) {
1525 MachineBasicBlock *MBB = CI.I->getParent();
1526
1527 // Be sure to use .addOperand(), and not .addReg() with these. We want to be
1528 // sure we preserve the subregister index and any register flags set on them.
1529 const MachineOperand *AddrReg =
1530 TII->getNamedOperand(*CI.I, AMDGPU::OpName::addr);
1531 const MachineOperand *Data0 =
1532 TII->getNamedOperand(*CI.I, AMDGPU::OpName::data0);
1533 const MachineOperand *Data1 =
1534 TII->getNamedOperand(*Paired.I, AMDGPU::OpName::data0);
1535
1536 unsigned NewOffset0 = CI.Offset;
1537 unsigned NewOffset1 = Paired.Offset;
1538 unsigned Opc = getWrite2Opcode(CI);
1539
1540 if (NewOffset0 > NewOffset1) {
1541 // Canonicalize the merged instruction so the smaller offset comes first.
1542 std::swap(NewOffset0, NewOffset1);
1543 std::swap(Data0, Data1);
1544 }
1545
1546 assert((isUInt<8>(NewOffset0) && isUInt<8>(NewOffset1)) &&
1547 (NewOffset0 != NewOffset1) && "Computed offset doesn't fit");
1548
1549 const MCInstrDesc &Write2Desc = TII->get(Opc);
1550 DebugLoc DL =
1551 DebugLoc::getMergedLocation(CI.I->getDebugLoc(), Paired.I->getDebugLoc());
1552
1553 Register BaseReg = AddrReg->getReg();
1554 unsigned BaseSubReg = AddrReg->getSubReg();
1555 RegState BaseRegFlags = {};
1556 if (CI.BaseOff) {
1557 Register ImmReg = MRI->createVirtualRegister(&AMDGPU::SReg_32RegClass);
1558 BuildMI(*MBB, InsertBefore, DL, TII->get(AMDGPU::S_MOV_B32), ImmReg)
1559 .addImm(CI.BaseOff);
1560
1561 BaseReg = MRI->createVirtualRegister(&AMDGPU::VGPR_32RegClass);
1562 BaseRegFlags = RegState::Kill;
1563
1564 TII->getAddNoCarry(*MBB, InsertBefore, DL, BaseReg)
1565 .addReg(ImmReg)
1566 .addReg(AddrReg->getReg(), {}, BaseSubReg)
1567 .addImm(0); // clamp bit
1568 BaseSubReg = 0;
1569 }
1570
1571 MachineInstrBuilder Write2 =
1572 BuildMI(*MBB, InsertBefore, DL, Write2Desc)
1573 .addReg(BaseReg, BaseRegFlags, BaseSubReg) // addr
1574 .add(*Data0) // data0
1575 .add(*Data1) // data1
1576 .addImm(NewOffset0) // offset0
1577 .addImm(NewOffset1) // offset1
1578 .addImm(0) // gds
1579 .cloneMergedMemRefs({&*CI.I, &*Paired.I});
1580
1581 CI.I->eraseFromParent();
1582 Paired.I->eraseFromParent();
1583
1584 LLVM_DEBUG(dbgs() << "Inserted write2 inst: " << *Write2 << '\n');
1585 return Write2;
1586}
1587
1589SILoadStoreOptimizer::mergeImagePair(CombineInfo &CI, CombineInfo &Paired,
1590 MachineBasicBlock::iterator InsertBefore) {
1591 MachineBasicBlock *MBB = CI.I->getParent();
1592 DebugLoc DL =
1593 DebugLoc::getMergedLocation(CI.I->getDebugLoc(), Paired.I->getDebugLoc());
1594
1595 const unsigned Opcode = getNewOpcode(CI, Paired);
1596
1597 const TargetRegisterClass *SuperRC = getTargetRegisterClass(CI, Paired);
1598
1599 Register DestReg = MRI->createVirtualRegister(SuperRC);
1600 unsigned MergedDMask = CI.DMask | Paired.DMask;
1601 unsigned DMaskIdx =
1602 AMDGPU::getNamedOperandIdx(CI.I->getOpcode(), AMDGPU::OpName::dmask);
1603
1604 auto MIB = BuildMI(*MBB, InsertBefore, DL, TII->get(Opcode), DestReg);
1605 for (unsigned I = 1, E = (*CI.I).getNumOperands(); I != E; ++I) {
1606 if (I == DMaskIdx)
1607 MIB.addImm(MergedDMask);
1608 else
1609 MIB.add((*CI.I).getOperand(I));
1610 }
1611
1612 // It shouldn't be possible to get this far if the two instructions
1613 // don't have a single memoperand, because MachineInstr::mayAlias()
1614 // will return true if this is the case.
1615 assert(CI.I->hasOneMemOperand() && Paired.I->hasOneMemOperand());
1616
1617 MachineInstr *New = MIB.addMemOperand(combineKnownAdjacentMMOs(CI, Paired));
1618
1619 copyToDestRegs(CI, Paired, InsertBefore, DL, AMDGPU::OpName::vdata, DestReg);
1620
1621 CI.I->eraseFromParent();
1622 Paired.I->eraseFromParent();
1623 return New;
1624}
1625
1626MachineBasicBlock::iterator SILoadStoreOptimizer::mergeSMemLoadImmPair(
1627 CombineInfo &CI, CombineInfo &Paired,
1628 MachineBasicBlock::iterator InsertBefore) {
1629 MachineBasicBlock *MBB = CI.I->getParent();
1630 DebugLoc DL =
1631 DebugLoc::getMergedLocation(CI.I->getDebugLoc(), Paired.I->getDebugLoc());
1632
1633 const unsigned Opcode = getNewOpcode(CI, Paired);
1634
1635 const TargetRegisterClass *SuperRC = getTargetRegisterClass(CI, Paired);
1636
1637 Register DestReg = MRI->createVirtualRegister(SuperRC);
1638 unsigned MergedOffset = std::min(CI.Offset, Paired.Offset);
1639
1640 // It shouldn't be possible to get this far if the two instructions
1641 // don't have a single memoperand, because MachineInstr::mayAlias()
1642 // will return true if this is the case.
1643 assert(CI.I->hasOneMemOperand() && Paired.I->hasOneMemOperand());
1644
1645 MachineInstrBuilder New =
1646 BuildMI(*MBB, InsertBefore, DL, TII->get(Opcode), DestReg)
1647 .add(*TII->getNamedOperand(*CI.I, AMDGPU::OpName::sbase));
1648 if (CI.InstClass == S_BUFFER_LOAD_SGPR_IMM)
1649 New.add(*TII->getNamedOperand(*CI.I, AMDGPU::OpName::soffset));
1650 New.addImm(MergedOffset);
1651 New.addImm(CI.CPol).addMemOperand(combineKnownAdjacentMMOs(CI, Paired));
1652
1653 copyToDestRegs(CI, Paired, InsertBefore, DL, AMDGPU::OpName::sdst, DestReg);
1654
1655 CI.I->eraseFromParent();
1656 Paired.I->eraseFromParent();
1657 return New;
1658}
1659
1660MachineBasicBlock::iterator SILoadStoreOptimizer::mergeBufferLoadPair(
1661 CombineInfo &CI, CombineInfo &Paired,
1662 MachineBasicBlock::iterator InsertBefore) {
1663 MachineBasicBlock *MBB = CI.I->getParent();
1664
1665 DebugLoc DL =
1666 DebugLoc::getMergedLocation(CI.I->getDebugLoc(), Paired.I->getDebugLoc());
1667
1668 const unsigned Opcode = getNewOpcode(CI, Paired);
1669
1670 const TargetRegisterClass *SuperRC = getTargetRegisterClass(CI, Paired);
1671
1672 // Copy to the new source register.
1673 Register DestReg = MRI->createVirtualRegister(SuperRC);
1674 unsigned MergedOffset = std::min(CI.Offset, Paired.Offset);
1675
1676 auto MIB = BuildMI(*MBB, InsertBefore, DL, TII->get(Opcode), DestReg);
1677
1678 AddressRegs Regs = getRegs(Opcode, *TII);
1679
1680 if (Regs.VAddr)
1681 MIB.add(*TII->getNamedOperand(*CI.I, AMDGPU::OpName::vaddr));
1682
1683 // It shouldn't be possible to get this far if the two instructions
1684 // don't have a single memoperand, because MachineInstr::mayAlias()
1685 // will return true if this is the case.
1686 assert(CI.I->hasOneMemOperand() && Paired.I->hasOneMemOperand());
1687
1688 MachineInstr *New =
1689 MIB.add(*TII->getNamedOperand(*CI.I, AMDGPU::OpName::srsrc))
1690 .add(*TII->getNamedOperand(*CI.I, AMDGPU::OpName::soffset))
1691 .addImm(MergedOffset) // offset
1692 .addImm(CI.CPol) // cpol
1693 .addImm(0) // swz
1694 .addMemOperand(combineKnownAdjacentMMOs(CI, Paired));
1695
1696 copyToDestRegs(CI, Paired, InsertBefore, DL, AMDGPU::OpName::vdata, DestReg);
1697
1698 CI.I->eraseFromParent();
1699 Paired.I->eraseFromParent();
1700 return New;
1701}
1702
1703MachineBasicBlock::iterator SILoadStoreOptimizer::mergeTBufferLoadPair(
1704 CombineInfo &CI, CombineInfo &Paired,
1705 MachineBasicBlock::iterator InsertBefore) {
1706 MachineBasicBlock *MBB = CI.I->getParent();
1707
1708 DebugLoc DL =
1709 DebugLoc::getMergedLocation(CI.I->getDebugLoc(), Paired.I->getDebugLoc());
1710
1711 const unsigned Opcode = getNewOpcode(CI, Paired);
1712
1713 const TargetRegisterClass *SuperRC = getTargetRegisterClass(CI, Paired);
1714
1715 // Copy to the new source register.
1716 Register DestReg = MRI->createVirtualRegister(SuperRC);
1717 unsigned MergedOffset = std::min(CI.Offset, Paired.Offset);
1718
1719 auto MIB = BuildMI(*MBB, InsertBefore, DL, TII->get(Opcode), DestReg);
1720
1721 AddressRegs Regs = getRegs(Opcode, *TII);
1722
1723 if (Regs.VAddr)
1724 MIB.add(*TII->getNamedOperand(*CI.I, AMDGPU::OpName::vaddr));
1725
1726 // For 8-bit or 16-bit tbuffer formats there is no 3-component encoding.
1727 // If the combined count is 3 (e.g. X+X+X or XY+X), promote to 4 components
1728 // and use XYZ of XYZW to enable the merge.
1729 unsigned NumCombinedComponents = CI.Width + Paired.Width;
1730 if (NumCombinedComponents == 3 && CI.EltSize <= 2)
1731 NumCombinedComponents = 4;
1732 unsigned JoinedFormat =
1733 getBufferFormatWithCompCount(CI.Format, NumCombinedComponents, *STM);
1734
1735 // It shouldn't be possible to get this far if the two instructions
1736 // don't have a single memoperand, because MachineInstr::mayAlias()
1737 // will return true if this is the case.
1738 assert(CI.I->hasOneMemOperand() && Paired.I->hasOneMemOperand());
1739
1740 MachineInstr *New =
1741 MIB.add(*TII->getNamedOperand(*CI.I, AMDGPU::OpName::srsrc))
1742 .add(*TII->getNamedOperand(*CI.I, AMDGPU::OpName::soffset))
1743 .addImm(MergedOffset) // offset
1744 .addImm(JoinedFormat) // format
1745 .addImm(CI.CPol) // cpol
1746 .addImm(0) // swz
1747 .addMemOperand(combineKnownAdjacentMMOs(CI, Paired));
1748
1749 copyToDestRegs(CI, Paired, InsertBefore, DL, AMDGPU::OpName::vdata, DestReg);
1750
1751 CI.I->eraseFromParent();
1752 Paired.I->eraseFromParent();
1753 return New;
1754}
1755
1756MachineBasicBlock::iterator SILoadStoreOptimizer::mergeTBufferStorePair(
1757 CombineInfo &CI, CombineInfo &Paired,
1758 MachineBasicBlock::iterator InsertBefore) {
1759 MachineBasicBlock *MBB = CI.I->getParent();
1760 DebugLoc DL =
1761 DebugLoc::getMergedLocation(CI.I->getDebugLoc(), Paired.I->getDebugLoc());
1762
1763 const unsigned Opcode = getNewOpcode(CI, Paired);
1764
1765 Register SrcReg =
1766 copyFromSrcRegs(CI, Paired, InsertBefore, DL, AMDGPU::OpName::vdata);
1767
1768 auto MIB = BuildMI(*MBB, InsertBefore, DL, TII->get(Opcode))
1769 .addReg(SrcReg, RegState::Kill);
1770
1771 AddressRegs Regs = getRegs(Opcode, *TII);
1772
1773 if (Regs.VAddr)
1774 MIB.add(*TII->getNamedOperand(*CI.I, AMDGPU::OpName::vaddr));
1775
1776 // For 8-bit or 16-bit tbuffer formats there is no 3-component encoding.
1777 // If the combined count is 3 (e.g. X+X+X or XY+X), promote to 4 components
1778 // and use XYZ of XYZW to enable the merge.
1779 unsigned NumCombinedComponents = CI.Width + Paired.Width;
1780 if (NumCombinedComponents == 3 && CI.EltSize <= 2)
1781 NumCombinedComponents = 4;
1782 unsigned JoinedFormat =
1783 getBufferFormatWithCompCount(CI.Format, NumCombinedComponents, *STM);
1784
1785 // It shouldn't be possible to get this far if the two instructions
1786 // don't have a single memoperand, because MachineInstr::mayAlias()
1787 // will return true if this is the case.
1788 assert(CI.I->hasOneMemOperand() && Paired.I->hasOneMemOperand());
1789
1790 MachineInstr *New =
1791 MIB.add(*TII->getNamedOperand(*CI.I, AMDGPU::OpName::srsrc))
1792 .add(*TII->getNamedOperand(*CI.I, AMDGPU::OpName::soffset))
1793 .addImm(std::min(CI.Offset, Paired.Offset)) // offset
1794 .addImm(JoinedFormat) // format
1795 .addImm(CI.CPol) // cpol
1796 .addImm(0) // swz
1797 .addMemOperand(combineKnownAdjacentMMOs(CI, Paired));
1798
1799 CI.I->eraseFromParent();
1800 Paired.I->eraseFromParent();
1801 return New;
1802}
1803
1804MachineBasicBlock::iterator SILoadStoreOptimizer::mergeFlatLoadPair(
1805 CombineInfo &CI, CombineInfo &Paired,
1806 MachineBasicBlock::iterator InsertBefore) {
1807 MachineBasicBlock *MBB = CI.I->getParent();
1808
1809 DebugLoc DL =
1810 DebugLoc::getMergedLocation(CI.I->getDebugLoc(), Paired.I->getDebugLoc());
1811
1812 const unsigned Opcode = getNewOpcode(CI, Paired);
1813
1814 const TargetRegisterClass *SuperRC = getTargetRegisterClass(CI, Paired);
1815 Register DestReg = MRI->createVirtualRegister(SuperRC);
1816
1817 auto MIB = BuildMI(*MBB, InsertBefore, DL, TII->get(Opcode), DestReg);
1818
1819 if (auto *SAddr = TII->getNamedOperand(*CI.I, AMDGPU::OpName::saddr))
1820 MIB.add(*SAddr);
1821
1822 MachineInstr *New =
1823 MIB.add(*TII->getNamedOperand(*CI.I, AMDGPU::OpName::vaddr))
1824 .addImm(std::min(CI.Offset, Paired.Offset))
1825 .addImm(CI.CPol)
1826 .addMemOperand(combineKnownAdjacentMMOs(CI, Paired));
1827
1828 copyToDestRegs(CI, Paired, InsertBefore, DL, AMDGPU::OpName::vdst, DestReg);
1829
1830 CI.I->eraseFromParent();
1831 Paired.I->eraseFromParent();
1832 return New;
1833}
1834
1835MachineBasicBlock::iterator SILoadStoreOptimizer::mergeFlatStorePair(
1836 CombineInfo &CI, CombineInfo &Paired,
1837 MachineBasicBlock::iterator InsertBefore) {
1838 MachineBasicBlock *MBB = CI.I->getParent();
1839
1840 DebugLoc DL =
1841 DebugLoc::getMergedLocation(CI.I->getDebugLoc(), Paired.I->getDebugLoc());
1842
1843 const unsigned Opcode = getNewOpcode(CI, Paired);
1844
1845 Register SrcReg =
1846 copyFromSrcRegs(CI, Paired, InsertBefore, DL, AMDGPU::OpName::vdata);
1847
1848 auto MIB = BuildMI(*MBB, InsertBefore, DL, TII->get(Opcode))
1849 .add(*TII->getNamedOperand(*CI.I, AMDGPU::OpName::vaddr))
1850 .addReg(SrcReg, RegState::Kill);
1851
1852 if (auto *SAddr = TII->getNamedOperand(*CI.I, AMDGPU::OpName::saddr))
1853 MIB.add(*SAddr);
1854
1855 MachineInstr *New =
1856 MIB.addImm(std::min(CI.Offset, Paired.Offset))
1857 .addImm(CI.CPol)
1858 .addMemOperand(combineKnownAdjacentMMOs(CI, Paired));
1859
1860 CI.I->eraseFromParent();
1861 Paired.I->eraseFromParent();
1862 return New;
1863}
1864
1867 unsigned Width) {
1868 // Conservatively returns true if not found the MMO.
1869 return STM.isXNACKEnabled() &&
1870 (MMOs.size() != 1 || MMOs[0]->getAlign().value() < Width * 4);
1871}
1872
1873unsigned SILoadStoreOptimizer::getNewOpcode(const CombineInfo &CI,
1874 const CombineInfo &Paired) {
1875 const unsigned Width = CI.Width + Paired.Width;
1876
1877 switch (getCommonInstClass(CI, Paired)) {
1878 default:
1879 assert(CI.InstClass == BUFFER_LOAD || CI.InstClass == BUFFER_STORE);
1880 // FIXME: Handle d16 correctly
1881 return AMDGPU::getMUBUFOpcode(AMDGPU::getMUBUFBaseOpcode(CI.I->getOpcode()),
1882 Width);
1883 case TBUFFER_LOAD:
1884 case TBUFFER_STORE:
1885 return AMDGPU::getMTBUFOpcode(AMDGPU::getMTBUFBaseOpcode(CI.I->getOpcode()),
1886 Width);
1887
1888 case UNKNOWN:
1889 llvm_unreachable("Unknown instruction class");
1890 case S_BUFFER_LOAD_IMM: {
1891 // If XNACK is enabled, use the constrained opcodes when the first load is
1892 // under-aligned.
1893 bool NeedsConstrainedOpc =
1894 needsConstrainedOpcode(*STM, CI.I->memoperands(), Width);
1895 switch (Width) {
1896 default:
1897 return 0;
1898 case 2:
1899 return NeedsConstrainedOpc ? AMDGPU::S_BUFFER_LOAD_DWORDX2_IMM_ec
1900 : AMDGPU::S_BUFFER_LOAD_DWORDX2_IMM;
1901 case 3:
1902 return NeedsConstrainedOpc ? AMDGPU::S_BUFFER_LOAD_DWORDX3_IMM_ec
1903 : AMDGPU::S_BUFFER_LOAD_DWORDX3_IMM;
1904 case 4:
1905 return NeedsConstrainedOpc ? AMDGPU::S_BUFFER_LOAD_DWORDX4_IMM_ec
1906 : AMDGPU::S_BUFFER_LOAD_DWORDX4_IMM;
1907 case 8:
1908 return NeedsConstrainedOpc ? AMDGPU::S_BUFFER_LOAD_DWORDX8_IMM_ec
1909 : AMDGPU::S_BUFFER_LOAD_DWORDX8_IMM;
1910 }
1911 }
1912 case S_BUFFER_LOAD_SGPR_IMM: {
1913 // If XNACK is enabled, use the constrained opcodes when the first load is
1914 // under-aligned.
1915 bool NeedsConstrainedOpc =
1916 needsConstrainedOpcode(*STM, CI.I->memoperands(), Width);
1917 switch (Width) {
1918 default:
1919 return 0;
1920 case 2:
1921 return NeedsConstrainedOpc ? AMDGPU::S_BUFFER_LOAD_DWORDX2_SGPR_IMM_ec
1922 : AMDGPU::S_BUFFER_LOAD_DWORDX2_SGPR_IMM;
1923 case 3:
1924 return NeedsConstrainedOpc ? AMDGPU::S_BUFFER_LOAD_DWORDX3_SGPR_IMM_ec
1925 : AMDGPU::S_BUFFER_LOAD_DWORDX3_SGPR_IMM;
1926 case 4:
1927 return NeedsConstrainedOpc ? AMDGPU::S_BUFFER_LOAD_DWORDX4_SGPR_IMM_ec
1928 : AMDGPU::S_BUFFER_LOAD_DWORDX4_SGPR_IMM;
1929 case 8:
1930 return NeedsConstrainedOpc ? AMDGPU::S_BUFFER_LOAD_DWORDX8_SGPR_IMM_ec
1931 : AMDGPU::S_BUFFER_LOAD_DWORDX8_SGPR_IMM;
1932 }
1933 }
1934 case S_LOAD_IMM: {
1935 // If XNACK is enabled, use the constrained opcodes when the first load is
1936 // under-aligned.
1937 bool NeedsConstrainedOpc =
1938 needsConstrainedOpcode(*STM, CI.I->memoperands(), Width);
1939 switch (Width) {
1940 default:
1941 return 0;
1942 case 2:
1943 return NeedsConstrainedOpc ? AMDGPU::S_LOAD_DWORDX2_IMM_ec
1944 : AMDGPU::S_LOAD_DWORDX2_IMM;
1945 case 3:
1946 return NeedsConstrainedOpc ? AMDGPU::S_LOAD_DWORDX3_IMM_ec
1947 : AMDGPU::S_LOAD_DWORDX3_IMM;
1948 case 4:
1949 return NeedsConstrainedOpc ? AMDGPU::S_LOAD_DWORDX4_IMM_ec
1950 : AMDGPU::S_LOAD_DWORDX4_IMM;
1951 case 8:
1952 return NeedsConstrainedOpc ? AMDGPU::S_LOAD_DWORDX8_IMM_ec
1953 : AMDGPU::S_LOAD_DWORDX8_IMM;
1954 }
1955 }
1956 case GLOBAL_LOAD:
1957 switch (Width) {
1958 default:
1959 return 0;
1960 case 2:
1961 return AMDGPU::GLOBAL_LOAD_DWORDX2;
1962 case 3:
1963 return AMDGPU::GLOBAL_LOAD_DWORDX3;
1964 case 4:
1965 return AMDGPU::GLOBAL_LOAD_DWORDX4;
1966 }
1967 case GLOBAL_LOAD_SADDR:
1968 switch (Width) {
1969 default:
1970 return 0;
1971 case 2:
1972 return AMDGPU::GLOBAL_LOAD_DWORDX2_SADDR;
1973 case 3:
1974 return AMDGPU::GLOBAL_LOAD_DWORDX3_SADDR;
1975 case 4:
1976 return AMDGPU::GLOBAL_LOAD_DWORDX4_SADDR;
1977 }
1978 case GLOBAL_STORE:
1979 switch (Width) {
1980 default:
1981 return 0;
1982 case 2:
1983 return AMDGPU::GLOBAL_STORE_DWORDX2;
1984 case 3:
1985 return AMDGPU::GLOBAL_STORE_DWORDX3;
1986 case 4:
1987 return AMDGPU::GLOBAL_STORE_DWORDX4;
1988 }
1989 case GLOBAL_STORE_SADDR:
1990 switch (Width) {
1991 default:
1992 return 0;
1993 case 2:
1994 return AMDGPU::GLOBAL_STORE_DWORDX2_SADDR;
1995 case 3:
1996 return AMDGPU::GLOBAL_STORE_DWORDX3_SADDR;
1997 case 4:
1998 return AMDGPU::GLOBAL_STORE_DWORDX4_SADDR;
1999 }
2000 case FLAT_LOAD:
2001 switch (Width) {
2002 default:
2003 return 0;
2004 case 2:
2005 return AMDGPU::FLAT_LOAD_DWORDX2;
2006 case 3:
2007 return AMDGPU::FLAT_LOAD_DWORDX3;
2008 case 4:
2009 return AMDGPU::FLAT_LOAD_DWORDX4;
2010 }
2011 case FLAT_STORE:
2012 switch (Width) {
2013 default:
2014 return 0;
2015 case 2:
2016 return AMDGPU::FLAT_STORE_DWORDX2;
2017 case 3:
2018 return AMDGPU::FLAT_STORE_DWORDX3;
2019 case 4:
2020 return AMDGPU::FLAT_STORE_DWORDX4;
2021 }
2022 case FLAT_LOAD_SADDR:
2023 switch (Width) {
2024 default:
2025 return 0;
2026 case 2:
2027 return AMDGPU::FLAT_LOAD_DWORDX2_SADDR;
2028 case 3:
2029 return AMDGPU::FLAT_LOAD_DWORDX3_SADDR;
2030 case 4:
2031 return AMDGPU::FLAT_LOAD_DWORDX4_SADDR;
2032 }
2033 case FLAT_STORE_SADDR:
2034 switch (Width) {
2035 default:
2036 return 0;
2037 case 2:
2038 return AMDGPU::FLAT_STORE_DWORDX2_SADDR;
2039 case 3:
2040 return AMDGPU::FLAT_STORE_DWORDX3_SADDR;
2041 case 4:
2042 return AMDGPU::FLAT_STORE_DWORDX4_SADDR;
2043 }
2044 case MIMG:
2045 assert(((unsigned)llvm::popcount(CI.DMask | Paired.DMask) == Width) &&
2046 "No overlaps");
2047 return AMDGPU::getMaskedMIMGOp(CI.I->getOpcode(), Width);
2048 }
2049}
2050
2051std::pair<unsigned, unsigned>
2052SILoadStoreOptimizer::getSubRegIdxs(const CombineInfo &CI,
2053 const CombineInfo &Paired) {
2054 assert((CI.InstClass != MIMG ||
2055 ((unsigned)llvm::popcount(CI.DMask | Paired.DMask) ==
2056 CI.Width + Paired.Width)) &&
2057 "No overlaps");
2058
2059 unsigned Idx0;
2060 unsigned Idx1;
2061
2062 static const unsigned Idxs[5][4] = {
2063 {AMDGPU::sub0, AMDGPU::sub0_sub1, AMDGPU::sub0_sub1_sub2, AMDGPU::sub0_sub1_sub2_sub3},
2064 {AMDGPU::sub1, AMDGPU::sub1_sub2, AMDGPU::sub1_sub2_sub3, AMDGPU::sub1_sub2_sub3_sub4},
2065 {AMDGPU::sub2, AMDGPU::sub2_sub3, AMDGPU::sub2_sub3_sub4, AMDGPU::sub2_sub3_sub4_sub5},
2066 {AMDGPU::sub3, AMDGPU::sub3_sub4, AMDGPU::sub3_sub4_sub5, AMDGPU::sub3_sub4_sub5_sub6},
2067 {AMDGPU::sub4, AMDGPU::sub4_sub5, AMDGPU::sub4_sub5_sub6, AMDGPU::sub4_sub5_sub6_sub7},
2068 };
2069
2070 assert(CI.Width >= 1 && CI.Width <= 4);
2071 assert(Paired.Width >= 1 && Paired.Width <= 4);
2072
2073 if (Paired < CI) {
2074 Idx1 = Idxs[0][Paired.Width - 1];
2075 Idx0 = Idxs[Paired.Width][CI.Width - 1];
2076 } else {
2077 Idx0 = Idxs[0][CI.Width - 1];
2078 Idx1 = Idxs[CI.Width][Paired.Width - 1];
2079 }
2080
2081 return {Idx0, Idx1};
2082}
2083
2084const TargetRegisterClass *
2085SILoadStoreOptimizer::getTargetRegisterClass(const CombineInfo &CI,
2086 const CombineInfo &Paired) const {
2087 if (CI.InstClass == S_BUFFER_LOAD_IMM ||
2088 CI.InstClass == S_BUFFER_LOAD_SGPR_IMM || CI.InstClass == S_LOAD_IMM) {
2089 switch (CI.Width + Paired.Width) {
2090 default:
2091 return nullptr;
2092 case 2:
2093 return &AMDGPU::SReg_64_XEXECRegClass;
2094 case 3:
2095 return &AMDGPU::SGPR_96RegClass;
2096 case 4:
2097 return &AMDGPU::SGPR_128RegClass;
2098 case 8:
2099 return &AMDGPU::SGPR_256RegClass;
2100 case 16:
2101 return &AMDGPU::SGPR_512RegClass;
2102 }
2103 }
2104
2105 // FIXME: This should compute the instruction to use, and then use the result
2106 // of TII->getRegClass.
2107 unsigned BitWidth = 32 * (CI.Width + Paired.Width);
2108 return TRI->isAGPRClass(getDataRegClass(*CI.I))
2109 ? TRI->getAGPRClassForBitWidth(BitWidth)
2110 : TRI->getVGPRClassForBitWidth(BitWidth);
2111}
2112
2113MachineBasicBlock::iterator SILoadStoreOptimizer::mergeBufferStorePair(
2114 CombineInfo &CI, CombineInfo &Paired,
2115 MachineBasicBlock::iterator InsertBefore) {
2116 MachineBasicBlock *MBB = CI.I->getParent();
2117 DebugLoc DL =
2118 DebugLoc::getMergedLocation(CI.I->getDebugLoc(), Paired.I->getDebugLoc());
2119
2120 const unsigned Opcode = getNewOpcode(CI, Paired);
2121
2122 Register SrcReg =
2123 copyFromSrcRegs(CI, Paired, InsertBefore, DL, AMDGPU::OpName::vdata);
2124
2125 auto MIB = BuildMI(*MBB, InsertBefore, DL, TII->get(Opcode))
2126 .addReg(SrcReg, RegState::Kill);
2127
2128 AddressRegs Regs = getRegs(Opcode, *TII);
2129
2130 if (Regs.VAddr)
2131 MIB.add(*TII->getNamedOperand(*CI.I, AMDGPU::OpName::vaddr));
2132
2133
2134 // It shouldn't be possible to get this far if the two instructions
2135 // don't have a single memoperand, because MachineInstr::mayAlias()
2136 // will return true if this is the case.
2137 assert(CI.I->hasOneMemOperand() && Paired.I->hasOneMemOperand());
2138
2139 MachineInstr *New =
2140 MIB.add(*TII->getNamedOperand(*CI.I, AMDGPU::OpName::srsrc))
2141 .add(*TII->getNamedOperand(*CI.I, AMDGPU::OpName::soffset))
2142 .addImm(std::min(CI.Offset, Paired.Offset)) // offset
2143 .addImm(CI.CPol) // cpol
2144 .addImm(0) // swz
2145 .addMemOperand(combineKnownAdjacentMMOs(CI, Paired));
2146
2147 CI.I->eraseFromParent();
2148 Paired.I->eraseFromParent();
2149 return New;
2150}
2151
2152MachineOperand
2153SILoadStoreOptimizer::createRegOrImm(int32_t Val, MachineInstr &MI) const {
2154 APInt V(32, Val, true);
2155 if (TII->isInlineConstant(V))
2156 return MachineOperand::CreateImm(Val);
2157
2158 Register Reg = MRI->createVirtualRegister(&AMDGPU::SReg_32RegClass);
2159 MachineInstr *Mov =
2160 BuildMI(*MI.getParent(), MI.getIterator(), MI.getDebugLoc(),
2161 TII->get(AMDGPU::S_MOV_B32), Reg)
2162 .addImm(Val);
2163 (void)Mov;
2164 LLVM_DEBUG(dbgs() << " "; Mov->dump());
2165 return MachineOperand::CreateReg(Reg, false);
2166}
2167
2168// Compute base address using Addr and return the final register.
2169Register SILoadStoreOptimizer::computeBase(MachineInstr &MI,
2170 const MemAddress &Addr) const {
2171 MachineBasicBlock *MBB = MI.getParent();
2172 MachineBasicBlock::iterator MBBI = MI.getIterator();
2173 const DebugLoc &DL = MI.getDebugLoc();
2174
2175 LLVM_DEBUG(dbgs() << " Re-Computed Anchor-Base:\n");
2176
2177 // Use V_ADD_U64_e64 when the original pattern used it (gfx1250+)
2178 if (Addr.Base.UseV64Pattern) {
2179 Register FullDestReg = MRI->createVirtualRegister(
2180 TII->getRegClass(TII->get(AMDGPU::V_ADD_U64_e64), 0));
2181
2182 // Load the 64-bit offset into an SGPR pair if needed
2183 Register OffsetReg = MRI->createVirtualRegister(&AMDGPU::SReg_64RegClass);
2184 MachineInstr *MovOffset =
2185 BuildMI(*MBB, MBBI, DL, TII->get(AMDGPU::S_MOV_B64_IMM_PSEUDO),
2186 OffsetReg)
2187 .addImm(Addr.Offset);
2188 MachineInstr *Add64 =
2189 BuildMI(*MBB, MBBI, DL, TII->get(AMDGPU::V_ADD_U64_e64), FullDestReg)
2190 .addReg(Addr.Base.LoReg)
2191 .addReg(OffsetReg, RegState::Kill)
2192 .addImm(0);
2193 (void)MovOffset;
2194 (void)Add64;
2195 LLVM_DEBUG(dbgs() << " " << *MovOffset << "\n";
2196 dbgs() << " " << *Add64 << "\n\n";);
2197
2198 return FullDestReg;
2199 }
2200
2201 // Original carry-chain pattern (V_ADD_CO_U32 + V_ADDC_U32)
2202 assert((TRI->getRegSizeInBits(Addr.Base.LoReg, *MRI) == 32 ||
2203 Addr.Base.LoSubReg) &&
2204 "Expected 32-bit Base-Register-Low!!");
2205
2206 assert((TRI->getRegSizeInBits(Addr.Base.HiReg, *MRI) == 32 ||
2207 Addr.Base.HiSubReg) &&
2208 "Expected 32-bit Base-Register-Hi!!");
2209
2210 MachineOperand OffsetLo = createRegOrImm(static_cast<int32_t>(Addr.Offset), MI);
2211 MachineOperand OffsetHi =
2212 createRegOrImm(static_cast<int32_t>(Addr.Offset >> 32), MI);
2213
2214 const auto *CarryRC = TRI->getWaveMaskRegClass();
2215 Register CarryReg = MRI->createVirtualRegister(CarryRC);
2216 Register DeadCarryReg = MRI->createVirtualRegister(CarryRC);
2217
2218 Register DestSub0 = MRI->createVirtualRegister(&AMDGPU::VGPR_32RegClass);
2219 Register DestSub1 = MRI->createVirtualRegister(&AMDGPU::VGPR_32RegClass);
2220 MachineInstr *LoHalf =
2221 BuildMI(*MBB, MBBI, DL, TII->get(AMDGPU::V_ADD_CO_U32_e64), DestSub0)
2222 .addReg(CarryReg, RegState::Define)
2223 .addReg(Addr.Base.LoReg, {}, Addr.Base.LoSubReg)
2224 .add(OffsetLo)
2225 .addImm(0); // clamp bit
2226
2227 MachineInstr *HiHalf =
2228 BuildMI(*MBB, MBBI, DL, TII->get(AMDGPU::V_ADDC_U32_e64), DestSub1)
2229 .addReg(DeadCarryReg, RegState::Define | RegState::Dead)
2230 .addReg(Addr.Base.HiReg, {}, Addr.Base.HiSubReg)
2231 .add(OffsetHi)
2232 .addReg(CarryReg, RegState::Kill)
2233 .addImm(0); // clamp bit
2234
2235 Register FullDestReg = MRI->createVirtualRegister(TRI->getVGPR64Class());
2236 MachineInstr *FullBase =
2237 BuildMI(*MBB, MBBI, DL, TII->get(TargetOpcode::REG_SEQUENCE), FullDestReg)
2238 .addReg(DestSub0)
2239 .addImm(AMDGPU::sub0)
2240 .addReg(DestSub1)
2241 .addImm(AMDGPU::sub1);
2242
2243 (void)LoHalf;
2244 (void)HiHalf;
2245 (void)FullBase;
2246 LLVM_DEBUG(dbgs() << " " << *LoHalf << "\n";
2247 dbgs() << " " << *HiHalf << "\n";
2248 dbgs() << " " << *FullBase << "\n\n";);
2249
2250 return FullDestReg;
2251}
2252
2253// Update base and offset with the NewBase and NewOffset in MI.
2254void SILoadStoreOptimizer::updateBaseAndOffset(MachineInstr &MI,
2255 Register NewBase,
2256 int32_t NewOffset) const {
2257 auto *Base = TII->getNamedOperand(MI, AMDGPU::OpName::vaddr);
2258 Base->setReg(NewBase);
2259 Base->setIsKill(false);
2260 TII->getNamedOperand(MI, AMDGPU::OpName::offset)->setImm(NewOffset);
2261}
2262
2263// Helper to extract a 64-bit constant offset from a V_ADD_U64_e64 instruction.
2264// Returns true if successful, populating Addr with base register info and
2265// offset.
2266bool SILoadStoreOptimizer::processBaseWithConstOffset64(
2267 MachineInstr *AddDef, const MachineOperand &Base, MemAddress &Addr) const {
2268 if (!Base.isReg())
2269 return false;
2270
2271 MachineOperand *Src0 = TII->getNamedOperand(*AddDef, AMDGPU::OpName::src0);
2272 MachineOperand *Src1 = TII->getNamedOperand(*AddDef, AMDGPU::OpName::src1);
2273
2274 const MachineOperand *BaseOp = nullptr;
2275
2276 auto Offset = TII->getImmOrMaterializedImm(*Src1);
2277
2278 if (Offset) {
2279 BaseOp = Src0;
2280 Addr.Offset = *Offset;
2281 } else {
2282 // Both or neither are constants - can't handle this pattern
2283 return false;
2284 }
2285
2286 // Now extract the base register (which should be a 64-bit VGPR).
2287 Addr.Base.LoReg = BaseOp->getReg();
2288 Addr.Base.UseV64Pattern = true;
2289 return true;
2290}
2291
2292// Analyze Base and extracts:
2293// - 32bit base registers, subregisters
2294// - 64bit constant offset
2295// Expecting base computation as:
2296// %OFFSET0:sgpr_32 = S_MOV_B32 8000
2297// %LO:vgpr_32, %c:sreg_64_xexec =
2298// V_ADD_CO_U32_e64 %BASE_LO:vgpr_32, %103:sgpr_32,
2299// %HI:vgpr_32, = V_ADDC_U32_e64 %BASE_HI:vgpr_32, 0, killed %c:sreg_64_xexec
2300// %Base:vreg_64 =
2301// REG_SEQUENCE %LO:vgpr_32, %subreg.sub0, %HI:vgpr_32, %subreg.sub1
2302//
2303// Also handles V_ADD_U64_e64 pattern (gfx1250+):
2304// %OFFSET:sreg_64 = S_MOV_B64_IMM_PSEUDO 256
2305// %Base:vreg_64 = V_ADD_U64_e64 %BASE:vreg_64, %OFFSET:sreg_64, 0
2306void SILoadStoreOptimizer::processBaseWithConstOffset(const MachineOperand &Base,
2307 MemAddress &Addr) const {
2308 if (!Base.isReg())
2309 return;
2310
2311 MachineInstr *Def = MRI->getUniqueVRegDef(Base.getReg());
2312 if (!Def)
2313 return;
2314
2315 // Try V_ADD_U64_e64 pattern first (simpler, used on gfx1250+)
2316 if (Def->getOpcode() == AMDGPU::V_ADD_U64_e64) {
2317 if (processBaseWithConstOffset64(Def, Base, Addr))
2318 return;
2319 }
2320
2321 // Fall through to REG_SEQUENCE + V_ADD_CO_U32 + V_ADDC_U32 pattern
2322 if (Def->getOpcode() != AMDGPU::REG_SEQUENCE || Def->getNumOperands() != 5)
2323 return;
2324
2325 MachineOperand BaseLo = Def->getOperand(1);
2326 MachineOperand BaseHi = Def->getOperand(3);
2327 if (!BaseLo.isReg() || !BaseHi.isReg())
2328 return;
2329
2330 MachineInstr *BaseLoDef = MRI->getUniqueVRegDef(BaseLo.getReg());
2331 MachineInstr *BaseHiDef = MRI->getUniqueVRegDef(BaseHi.getReg());
2332
2333 if (!BaseLoDef || BaseLoDef->getOpcode() != AMDGPU::V_ADD_CO_U32_e64 ||
2334 !BaseHiDef || BaseHiDef->getOpcode() != AMDGPU::V_ADDC_U32_e64)
2335 return;
2336
2337 MachineOperand *Src0 = TII->getNamedOperand(*BaseLoDef, AMDGPU::OpName::src0);
2338 MachineOperand *Src1 = TII->getNamedOperand(*BaseLoDef, AMDGPU::OpName::src1);
2339
2340 auto Offset0P = TII->getImmOrMaterializedImm(*Src0);
2341 if (Offset0P)
2342 BaseLo = *Src1;
2343 else {
2344 if (!(Offset0P = TII->getImmOrMaterializedImm(*Src1)))
2345 return;
2346 BaseLo = *Src0;
2347 }
2348
2349 if (!BaseLo.isReg())
2350 return;
2351
2352 Src0 = TII->getNamedOperand(*BaseHiDef, AMDGPU::OpName::src0);
2353 Src1 = TII->getNamedOperand(*BaseHiDef, AMDGPU::OpName::src1);
2354
2355 if (Src0->isImm())
2356 std::swap(Src0, Src1);
2357
2358 if (!Src1->isImm() || Src0->isImm())
2359 return;
2360
2361 uint64_t Offset1 = Src1->getImm();
2362 BaseHi = *Src0;
2363
2364 if (!BaseHi.isReg())
2365 return;
2366
2367 Addr.Base.LoReg = BaseLo.getReg();
2368 Addr.Base.HiReg = BaseHi.getReg();
2369 Addr.Base.LoSubReg = BaseLo.getSubReg();
2370 Addr.Base.HiSubReg = BaseHi.getSubReg();
2371 Addr.Offset = (*Offset0P & 0x00000000ffffffff) | (Offset1 << 32);
2372}
2373
2374// Maintain the correct LDS address for async loads and stores.
2375// It becomes incorrect when promoteConstantOffsetToImm adds an offset only
2376// meant for the global address operand. For async loads the LDS address is in
2377// vdst. For async stores, the LDS address is in vdata.
2378void SILoadStoreOptimizer::updateAsyncLDSAddress(MachineInstr &MI,
2379 int32_t OffsetDiff) const {
2380 if (!TII->usesASYNC_CNT(MI) || OffsetDiff == 0)
2381 return;
2382
2383 MachineOperand *LDSAddr = TII->getNamedOperand(MI, AMDGPU::OpName::vdst);
2384 if (!LDSAddr)
2385 LDSAddr = TII->getNamedOperand(MI, AMDGPU::OpName::vdata);
2386 assert(LDSAddr);
2387
2388 Register OldReg = LDSAddr->getReg();
2389 Register NewReg = MRI->createVirtualRegister(MRI->getRegClass(OldReg));
2390 MachineBasicBlock &MBB = *MI.getParent();
2391 const DebugLoc &DL = MI.getDebugLoc();
2392 BuildMI(MBB, MI, DL, TII->get(AMDGPU::V_ADD_U32_e64), NewReg)
2393 .addReg(OldReg)
2394 .addImm(-OffsetDiff)
2395 .addImm(0);
2396
2397 LDSAddr->setReg(NewReg);
2398}
2399
2400bool SILoadStoreOptimizer::promoteConstantOffsetToImm(
2401 MachineInstr &MI,
2402 MemInfoMap &Visited,
2403 SmallPtrSet<MachineInstr *, 4> &AnchorList) const {
2404
2405 if (!STM->hasFlatInstOffsets() || !SIInstrInfo::isFLAT(MI))
2406 return false;
2407
2408 // TODO: Support FLAT_SCRATCH. Currently code expects 64-bit pointers.
2410 return false;
2411
2414
2416 ? AMDGPU::FlatAddrSpace::FlatGlobal
2417 : AMDGPU::FlatAddrSpace::FLAT;
2418 bool AllowNegativeOffset =
2419 TII->allowNegativeFlatOffset(FlatVariant) && !TII->usesASYNC_CNT(MI);
2420 // The async global instructions use i24 offset for global address but u16
2421 // offset for LDS address. In this case, we just only promote when the offset
2422 // is u16.
2423 bool IsOffsetU16 = TII->usesASYNC_CNT(MI);
2424
2425 if (AnchorList.count(&MI))
2426 return false;
2427
2428 LLVM_DEBUG(dbgs() << "\nTryToPromoteConstantOffsetToImmFor "; MI.dump());
2429
2430 if (TII->getNamedOperand(MI, AMDGPU::OpName::offset)->getImm()) {
2431 LLVM_DEBUG(dbgs() << " Const-offset is already promoted.\n";);
2432 return false;
2433 }
2434
2435 // Step1: Find the base-registers and a 64bit constant offset.
2436 MachineOperand &Base = *TII->getNamedOperand(MI, AMDGPU::OpName::vaddr);
2437 auto [It, Inserted] = Visited.try_emplace(&MI);
2438 MemAddress MAddr;
2439 if (Inserted) {
2440 processBaseWithConstOffset(Base, MAddr);
2441 It->second = MAddr;
2442 } else
2443 MAddr = It->second;
2444
2445 if (MAddr.Offset == 0) {
2446 LLVM_DEBUG(dbgs() << " Failed to extract constant-offset or there are no"
2447 " constant offsets that can be promoted.\n";);
2448 return false;
2449 }
2450
2451 LLVM_DEBUG(dbgs() << " BASE: {" << printReg(MAddr.Base.HiReg, TRI) << ", "
2452 << printReg(MAddr.Base.LoReg, TRI)
2453 << "} Offset: " << MAddr.Offset << "\n\n";);
2454
2455 // Step2: Traverse through MI's basic block and find an anchor(that has the
2456 // same base-registers) with the highest 13bit distance from MI's offset.
2457 // E.g. (64bit loads)
2458 // bb:
2459 // addr1 = &a + 4096; load1 = load(addr1, 0)
2460 // addr2 = &a + 6144; load2 = load(addr2, 0)
2461 // addr3 = &a + 8192; load3 = load(addr3, 0)
2462 // addr4 = &a + 10240; load4 = load(addr4, 0)
2463 // addr5 = &a + 12288; load5 = load(addr5, 0)
2464 //
2465 // Starting from the first load, the optimization will try to find a new base
2466 // from which (&a + 4096) has 13 bit distance. Both &a + 6144 and &a + 8192
2467 // has 13bit distance from &a + 4096. The heuristic considers &a + 8192
2468 // as the new-base(anchor) because of the maximum distance which can
2469 // accommodate more intermediate bases presumably.
2470 //
2471 // Step3: move (&a + 8192) above load1. Compute and promote offsets from
2472 // (&a + 8192) for load1, load2, load4.
2473 // addr = &a + 8192
2474 // load1 = load(addr, -4096)
2475 // load2 = load(addr, -2048)
2476 // load3 = load(addr, 0)
2477 // load4 = load(addr, 2048)
2478 // addr5 = &a + 12288; load5 = load(addr5, 0)
2479 //
2480 MachineInstr *AnchorInst = nullptr;
2481 MemAddress AnchorAddr;
2482 uint32_t MaxDist = std::numeric_limits<uint32_t>::min();
2484 bool MIIsAnchor = false;
2485
2486 MachineBasicBlock *MBB = MI.getParent();
2488 MachineBasicBlock::iterator MBBI = MI.getIterator();
2489 ++MBBI;
2490 const SITargetLowering *TLI = STM->getTargetLowering();
2491
2492 for ( ; MBBI != E; ++MBBI) {
2493 MachineInstr &MINext = *MBBI;
2494 // TODO: Support finding an anchor(with same base) from store addresses or
2495 // any other load addresses where the opcodes are different.
2496 if (MINext.getOpcode() != MI.getOpcode() ||
2497 TII->getNamedOperand(MINext, AMDGPU::OpName::offset)->getImm())
2498 continue;
2499
2500 const MachineOperand &BaseNext =
2501 *TII->getNamedOperand(MINext, AMDGPU::OpName::vaddr);
2502 MemAddress MAddrNext;
2503 auto [It, Inserted] = Visited.try_emplace(&MINext);
2504 if (Inserted) {
2505 processBaseWithConstOffset(BaseNext, MAddrNext);
2506 It->second = MAddrNext;
2507 } else
2508 MAddrNext = It->second;
2509
2510 if (MAddrNext.Base.LoReg != MAddr.Base.LoReg ||
2511 MAddrNext.Base.HiReg != MAddr.Base.HiReg ||
2512 MAddrNext.Base.LoSubReg != MAddr.Base.LoSubReg ||
2513 MAddrNext.Base.HiSubReg != MAddr.Base.HiSubReg)
2514 continue;
2515
2516 InstsWCommonBase.emplace_back(&MINext, MAddrNext.Offset);
2517
2518 if (AllowNegativeOffset) {
2519 int64_t Dist = MAddr.Offset - MAddrNext.Offset;
2520 TargetLoweringBase::AddrMode AM;
2521 AM.HasBaseReg = true;
2522 AM.BaseOffs = Dist;
2523 if (TLI->isLegalFlatAddressingMode(AM, AS) &&
2524 (uint32_t)std::abs(Dist) > MaxDist) {
2525 MaxDist = std::abs(Dist);
2526
2527 AnchorAddr = MAddrNext;
2528 AnchorInst = &MINext;
2529 }
2530 }
2531 }
2532
2533 // When negative offsets are not allowed, pick the candidate with the smallest
2534 // offset as anchor so all promoted offsets are non-negative. If MI itself has
2535 // the smallest offset, MI becomes the reference point (MIIsAnchor).
2536 if (!AllowNegativeOffset && !InstsWCommonBase.empty()) {
2537 for (auto &[Inst, Offset] : InstsWCommonBase) {
2538 int64_t Dist = MAddr.Offset - Offset;
2539 TargetLoweringBase::AddrMode AM;
2540 AM.HasBaseReg = true;
2541 AM.BaseOffs = Dist;
2542 if (Dist >= 0 && TLI->isLegalFlatAddressingMode(AM, AS) &&
2543 (!IsOffsetU16 || isUInt<16>(Dist)) &&
2544 (!AnchorInst || Offset < AnchorAddr.Offset)) {
2545 AnchorAddr = Visited[Inst];
2546 AnchorInst = Inst;
2547 }
2548 }
2549 if (!AnchorInst)
2550 MIIsAnchor = true;
2551 }
2552
2553 if (AnchorInst) {
2554 LLVM_DEBUG(dbgs() << " Anchor-Inst(with max-distance from Offset): ";
2555 AnchorInst->dump());
2556 LLVM_DEBUG(dbgs() << " Anchor-Offset from BASE: "
2557 << AnchorAddr.Offset << "\n\n");
2558
2559 // Instead of moving up, just re-compute anchor-instruction's base address.
2560 Register Base = computeBase(MI, AnchorAddr);
2561
2562 int32_t OffsetDiff = MAddr.Offset - AnchorAddr.Offset;
2563 updateBaseAndOffset(MI, Base, OffsetDiff);
2564 updateAsyncLDSAddress(MI, OffsetDiff);
2565 LLVM_DEBUG(dbgs() << " After promotion: "; MI.dump(););
2566
2567 for (auto [OtherMI, OtherOffset] : InstsWCommonBase) {
2568 TargetLoweringBase::AddrMode AM;
2569 AM.HasBaseReg = true;
2570 AM.BaseOffs = OtherOffset - AnchorAddr.Offset;
2571
2572 if (TLI->isLegalFlatAddressingMode(AM, AS) &&
2573 (AllowNegativeOffset || AM.BaseOffs >= 0) &&
2574 (!IsOffsetU16 || isUInt<16>(AM.BaseOffs))) {
2575 LLVM_DEBUG(dbgs() << " Promote Offset(" << OtherOffset; dbgs() << ")";
2576 OtherMI->dump());
2577 int32_t OtherOffsetDiff = OtherOffset - AnchorAddr.Offset;
2578 updateBaseAndOffset(*OtherMI, Base, OtherOffsetDiff);
2579 updateAsyncLDSAddress(*OtherMI, OtherOffsetDiff);
2580 LLVM_DEBUG(dbgs() << " After promotion: "; OtherMI->dump());
2581 }
2582 }
2583 AnchorList.insert(AnchorInst);
2584 return true;
2585 }
2586
2587 if (MIIsAnchor) {
2588 LLVM_DEBUG(dbgs() << " MI is anchor (smallest offset); promoting "
2589 "candidates relative to MI's base.\n");
2590
2591 Register Base = TII->getNamedOperand(MI, AMDGPU::OpName::vaddr)->getReg();
2592 bool AnyPromoted = false;
2593
2594 for (auto [OtherMI, OtherOffset] : InstsWCommonBase) {
2595 int64_t Dist = OtherOffset - MAddr.Offset;
2596 TargetLoweringBase::AddrMode AM;
2597 AM.HasBaseReg = true;
2598 AM.BaseOffs = Dist;
2599 if (Dist >= 0 && TLI->isLegalFlatAddressingMode(AM, AS) &&
2600 (!IsOffsetU16 || isUInt<16>(Dist))) {
2601 LLVM_DEBUG(dbgs() << " Promote Offset(" << OtherOffset << ")";
2602 OtherMI->dump());
2603 updateBaseAndOffset(*OtherMI, Base, Dist);
2604 updateAsyncLDSAddress(*OtherMI, Dist);
2605 LLVM_DEBUG(dbgs() << " After promotion: "; OtherMI->dump());
2606 AnyPromoted = true;
2607 }
2608 }
2609
2610 if (AnyPromoted) {
2611 TII->getNamedOperand(MI, AMDGPU::OpName::vaddr)->setIsKill(false);
2612 AnchorList.insert(&MI);
2613 return true;
2614 }
2615 }
2616
2617 return false;
2618}
2619
2620void SILoadStoreOptimizer::addInstToMergeableList(const CombineInfo &CI,
2621 std::list<std::list<CombineInfo> > &MergeableInsts) const {
2622 for (std::list<CombineInfo> &AddrList : MergeableInsts) {
2623 if (AddrList.front().InstClass == CI.InstClass &&
2624 AddrList.front().hasSameBaseAddress(CI)) {
2625 AddrList.emplace_back(CI);
2626 return;
2627 }
2628 }
2629
2630 // Base address not found, so add a new list.
2631 MergeableInsts.emplace_back(1, CI);
2632}
2633
2634std::pair<MachineBasicBlock::iterator, bool>
2635SILoadStoreOptimizer::collectMergeableInsts(
2637 MemInfoMap &Visited, SmallPtrSet<MachineInstr *, 4> &AnchorList,
2638 std::list<std::list<CombineInfo>> &MergeableInsts) const {
2639 bool Modified = false;
2640
2641 // Sort potential mergeable instructions into lists. One list per base address.
2642 unsigned Order = 0;
2643 MachineBasicBlock::iterator BlockI = Begin;
2644 for (; BlockI != End; ++BlockI) {
2645 MachineInstr &MI = *BlockI;
2646
2647 // We run this before checking if an address is mergeable, because it can produce
2648 // better code even if the instructions aren't mergeable.
2649 if (promoteConstantOffsetToImm(MI, Visited, AnchorList))
2650 Modified = true;
2651
2652 // Treat volatile accesses, ordered accesses and unmodeled side effects as
2653 // barriers. We can look after this barrier for separate merges.
2654 if (MI.hasOrderedMemoryRef() || MI.hasUnmodeledSideEffects()) {
2655 LLVM_DEBUG(dbgs() << "Breaking search on barrier: " << MI);
2656
2657 // Search will resume after this instruction in a separate merge list.
2658 ++BlockI;
2659 break;
2660 }
2661
2662 const InstClassEnum InstClass = getInstClass(MI.getOpcode(), *TII);
2663 if (InstClass == UNKNOWN)
2664 continue;
2665
2666 // Do not merge VMEM buffer instructions with "swizzled" bit set.
2667 int Swizzled =
2668 AMDGPU::getNamedOperandIdx(MI.getOpcode(), AMDGPU::OpName::swz);
2669 if (Swizzled != -1 && MI.getOperand(Swizzled).getImm())
2670 continue;
2671
2672 if (InstClass == TBUFFER_LOAD || InstClass == TBUFFER_STORE) {
2673 const MachineOperand *Fmt =
2674 TII->getNamedOperand(MI, AMDGPU::OpName::format);
2675 if (!AMDGPU::getGcnBufferFormatInfo(Fmt->getImm(), *STM)) {
2676 LLVM_DEBUG(dbgs() << "Skip tbuffer with unknown format: " << MI);
2677 continue;
2678 }
2679 }
2680
2681 CombineInfo CI;
2682 CI.setMI(MI, *this);
2683 CI.Order = Order++;
2684
2685 if (!CI.hasMergeableAddress(*MRI))
2686 continue;
2687
2688 LLVM_DEBUG(dbgs() << "Mergeable: " << MI);
2689
2690 addInstToMergeableList(CI, MergeableInsts);
2691 }
2692
2693 // At this point we have lists of Mergeable instructions.
2694 //
2695 // Part 2: Sort lists by offset and then for each CombineInfo object in the
2696 // list try to find an instruction that can be merged with I. If an instruction
2697 // is found, it is stored in the Paired field. If no instructions are found, then
2698 // the CombineInfo object is deleted from the list.
2699
2700 for (std::list<std::list<CombineInfo>>::iterator I = MergeableInsts.begin(),
2701 E = MergeableInsts.end(); I != E;) {
2702
2703 std::list<CombineInfo> &MergeList = *I;
2704 if (MergeList.size() <= 1) {
2705 // This means we have found only one instruction with a given address
2706 // that can be merged, and we need at least 2 instructions to do a merge,
2707 // so this list can be discarded.
2708 I = MergeableInsts.erase(I);
2709 continue;
2710 }
2711
2712 // Sort the lists by offsets, this way mergeable instructions will be
2713 // adjacent to each other in the list, which will make it easier to find
2714 // matches.
2715 MergeList.sort(
2716 [] (const CombineInfo &A, const CombineInfo &B) {
2717 return A.Offset < B.Offset;
2718 });
2719 ++I;
2720 }
2721
2722 return {BlockI, Modified};
2723}
2724
2725// Scan through looking for adjacent LDS operations with constant offsets from
2726// the same base register. We rely on the scheduler to do the hard work of
2727// clustering nearby loads, and assume these are all adjacent.
2728bool SILoadStoreOptimizer::optimizeBlock(
2729 std::list<std::list<CombineInfo> > &MergeableInsts) {
2730 bool Modified = false;
2731
2732 for (std::list<std::list<CombineInfo>>::iterator I = MergeableInsts.begin(),
2733 E = MergeableInsts.end(); I != E;) {
2734 std::list<CombineInfo> &MergeList = *I;
2735
2736 bool OptimizeListAgain = false;
2737 if (!optimizeInstsWithSameBaseAddr(MergeList, OptimizeListAgain)) {
2738 // We weren't able to make any changes, so delete the list so we don't
2739 // process the same instructions the next time we try to optimize this
2740 // block.
2741 I = MergeableInsts.erase(I);
2742 continue;
2743 }
2744
2745 Modified = true;
2746
2747 // We made changes, but also determined that there were no more optimization
2748 // opportunities, so we don't need to reprocess the list
2749 if (!OptimizeListAgain) {
2750 I = MergeableInsts.erase(I);
2751 continue;
2752 }
2753 OptimizeAgain = true;
2754 }
2755 return Modified;
2756}
2757
2758bool
2759SILoadStoreOptimizer::optimizeInstsWithSameBaseAddr(
2760 std::list<CombineInfo> &MergeList,
2761 bool &OptimizeListAgain) {
2762 if (MergeList.empty())
2763 return false;
2764
2765 bool Modified = false;
2766
2767 for (auto I = MergeList.begin(), Next = std::next(I); Next != MergeList.end();
2768 Next = std::next(I)) {
2769
2770 auto First = I;
2771 auto Second = Next;
2772
2773 if ((*First).Order > (*Second).Order)
2774 std::swap(First, Second);
2775 CombineInfo &CI = *First;
2776 CombineInfo &Paired = *Second;
2777
2778 CombineInfo *Where = checkAndPrepareMerge(CI, Paired);
2779 if (!Where) {
2780 ++I;
2781 continue;
2782 }
2783
2784 Modified = true;
2785
2786 LLVM_DEBUG(dbgs() << "Merging: " << *CI.I << " with: " << *Paired.I);
2787
2789 switch (CI.InstClass) {
2790 default:
2791 llvm_unreachable("unknown InstClass");
2792 break;
2793 case DS_READ:
2794 NewMI = mergeRead2Pair(CI, Paired, Where->I);
2795 break;
2796 case DS_WRITE:
2797 NewMI = mergeWrite2Pair(CI, Paired, Where->I);
2798 break;
2799 case S_BUFFER_LOAD_IMM:
2800 case S_BUFFER_LOAD_SGPR_IMM:
2801 case S_LOAD_IMM:
2802 NewMI = mergeSMemLoadImmPair(CI, Paired, Where->I);
2803 OptimizeListAgain |= CI.Width + Paired.Width < 8;
2804 break;
2805 case BUFFER_LOAD:
2806 NewMI = mergeBufferLoadPair(CI, Paired, Where->I);
2807 OptimizeListAgain |= CI.Width + Paired.Width < 4;
2808 break;
2809 case BUFFER_STORE:
2810 NewMI = mergeBufferStorePair(CI, Paired, Where->I);
2811 OptimizeListAgain |= CI.Width + Paired.Width < 4;
2812 break;
2813 case MIMG:
2814 NewMI = mergeImagePair(CI, Paired, Where->I);
2815 OptimizeListAgain |= CI.Width + Paired.Width < 4;
2816 break;
2817 case TBUFFER_LOAD:
2818 NewMI = mergeTBufferLoadPair(CI, Paired, Where->I);
2819 OptimizeListAgain |= CI.Width + Paired.Width < 4;
2820 break;
2821 case TBUFFER_STORE:
2822 NewMI = mergeTBufferStorePair(CI, Paired, Where->I);
2823 OptimizeListAgain |= CI.Width + Paired.Width < 4;
2824 break;
2825 case FLAT_LOAD:
2826 case FLAT_LOAD_SADDR:
2827 case GLOBAL_LOAD:
2828 case GLOBAL_LOAD_SADDR:
2829 NewMI = mergeFlatLoadPair(CI, Paired, Where->I);
2830 OptimizeListAgain |= CI.Width + Paired.Width < 4;
2831 break;
2832 case FLAT_STORE:
2833 case FLAT_STORE_SADDR:
2834 case GLOBAL_STORE:
2835 case GLOBAL_STORE_SADDR:
2836 NewMI = mergeFlatStorePair(CI, Paired, Where->I);
2837 OptimizeListAgain |= CI.Width + Paired.Width < 4;
2838 break;
2839 }
2840 CI.setMI(NewMI, *this);
2841 CI.Order = Where->Order;
2842 if (I == Second)
2843 I = Next;
2844
2845 MergeList.erase(Second);
2846 }
2847
2848 return Modified;
2849}
2850
2851bool SILoadStoreOptimizerLegacy::runOnMachineFunction(MachineFunction &MF) {
2852 if (skipFunction(MF.getFunction()))
2853 return false;
2854 return SILoadStoreOptimizer(
2855 &getAnalysis<AAResultsWrapperPass>().getAAResults())
2856 .run(MF);
2857}
2858
2859bool SILoadStoreOptimizer::run(MachineFunction &MF) {
2860 this->MF = &MF;
2861 STM = &MF.getSubtarget<GCNSubtarget>();
2862 if (!STM->loadStoreOptEnabled())
2863 return false;
2864
2865 TII = STM->getInstrInfo();
2866 TRI = &TII->getRegisterInfo();
2867
2868 MRI = &MF.getRegInfo();
2869
2870 LLVM_DEBUG(dbgs() << "Running SILoadStoreOptimizer\n");
2871
2872 bool Modified = false;
2873
2874 // Contains the list of instructions for which constant offsets are being
2875 // promoted to the IMM. This is tracked for an entire block at time.
2876 SmallPtrSet<MachineInstr *, 4> AnchorList;
2877 MemInfoMap Visited;
2878
2879 for (MachineBasicBlock &MBB : MF) {
2880 MachineBasicBlock::iterator SectionEnd;
2881 for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E;
2882 I = SectionEnd) {
2883 bool CollectModified;
2884 std::list<std::list<CombineInfo>> MergeableInsts;
2885
2886 // First pass: Collect list of all instructions we know how to merge in a
2887 // subset of the block.
2888 std::tie(SectionEnd, CollectModified) =
2889 collectMergeableInsts(I, E, Visited, AnchorList, MergeableInsts);
2890
2891 Modified |= CollectModified;
2892
2893 do {
2894 OptimizeAgain = false;
2895 Modified |= optimizeBlock(MergeableInsts);
2896 } while (OptimizeAgain);
2897 }
2898
2899 Visited.clear();
2900 AnchorList.clear();
2901 }
2902
2903 return Modified;
2904}
2905
2906PreservedAnalyses
2909 MFPropsModifier _(*this, MF);
2910
2911 if (MF.getFunction().hasOptNone())
2912 return PreservedAnalyses::all();
2913
2915 .getManager();
2916 AAResults &AA = FAM.getResult<AAManager>(MF.getFunction());
2917
2918 bool Changed = SILoadStoreOptimizer(&AA).run(MF);
2919 if (!Changed)
2920 return PreservedAnalyses::all();
2921
2924 return PA;
2925}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
INITIALIZE_PASS(AMDGPUImageIntrinsicOptimizer, DEBUG_TYPE, "AMDGPU Image Intrinsic Optimizer", false, false) char AMDGPUImageIntrinsicOptimizer void addInstToMergeableList(IntrinsicInst *II, SmallVector< SmallVector< IntrinsicInst *, 4 > > &MergeableInsts, const AMDGPU::ImageDimIntrinsicInfo *ImageDimIntr)
BasicBlock::iterator collectMergeableInsts(BasicBlock::iterator I, BasicBlock::iterator E, SmallVector< SmallVector< IntrinsicInst *, 4 > > &MergeableInsts)
Provides AMDGPU specific target descriptions.
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
MachineBasicBlock MachineBasicBlock::iterator MBBI
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
AMD GCN specific subclass of TargetSubtarget.
#define DEBUG_TYPE
#define op(i)
const HexagonInstrInfo * TII
#define _
static MaybeAlign getAlign(Value *Ptr)
IRTranslator LLVM IR MI
#define I(x, y, z)
Definition MD5.cpp:57
Register Reg
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
FunctionAnalysisManager FAM
#define INITIALIZE_PASS_DEPENDENCY(depName)
Definition PassSupport.h:42
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition PassSupport.h:44
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition PassSupport.h:39
static uint32_t mostAlignedValueInRange(uint32_t Lo, uint32_t Hi)
static bool needsConstrainedOpcode(const GCNSubtarget &STM, ArrayRef< MachineMemOperand * > MMOs, unsigned Width)
static void addDefsUsesToList(const MachineInstr &MI, DenseSet< Register > &RegDefs, DenseSet< Register > &RegUses)
static unsigned getBufferFormatWithCompCount(unsigned OldFormat, unsigned ComponentCount, const GCNSubtarget &STI)
static bool optimizeBlock(BasicBlock &BB, bool &ModifiedDT, const TargetTransformInfo &TTI, const DataLayout &DL, bool HasBranchDivergence, DomTreeUpdater *DTU)
#define LLVM_DEBUG(...)
Definition Debug.h:119
A manager for alias analyses.
A wrapper pass to provide the legacy pass manager access to a suitably prepared AAResults object.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition Pass.cpp:275
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
size_t size() const
Get the array size.
Definition ArrayRef.h:141
Represents analyses that only rely on functions' control flow.
Definition Analysis.h:73
A debug info location.
Definition DebugLoc.h:126
static LLVM_ABI DebugLoc getMergedLocation(DebugLoc LocA, DebugLoc LocB)
When two instructions are combined into a single instruction we also need to combine the original loc...
Definition DebugLoc.cpp:172
Implements a dense probed hash-table based set.
Definition DenseSet.h:281
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
bool hasOptNone() const
Do not optimize this function (-O0).
Definition Function.h:685
bool loadStoreOptEnabled() const
const SIInstrInfo * getInstrInfo() const override
bool hasDwordx3LoadStores() const
const SITargetLowering * getTargetLowering() const override
bool ldsRequiresM0Init() const
Return if most LDS instructions have an m0 use that require m0 to be initialized.
bool isXNACKEnabled() const
const HexagonRegisterInfo & getRegisterInfo() const
TypeSize getValue() const
unsigned getOpcode() const
Return the opcode number for this descriptor.
An RAII based helper class to modify MachineFunctionProperties when running pass.
MachineInstrBundleIterator< MachineInstr > iterator
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.
Properties which a MachineFunction may have at a given point in time.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags f, LLT MemTy, Align base_alignment, const AAMDNodes &AAInfo=AAMDNodes(), const MDNode *Ranges=nullptr, SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineInstrBuilder & cloneMergedMemRefs(ArrayRef< const MachineInstr * > OtherMIs) const
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
LLVM_ABI void dump() const
A description of a memory reference used in the backend.
LocationSize getSize() const
Return the size in bytes of the memory reference.
unsigned getAddrSpace() const
const MachinePointerInfo & getPointerInfo() const
MachineOperand class - Representation of each machine instruction operand.
unsigned getSubReg() const
int64_t getImm() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
static MachineOperand CreateImm(int64_t Val)
Register getReg() const
getReg - Returns the register number.
static MachineOperand CreateReg(Register Reg, bool isDef, bool isImp=false, bool isKill=false, bool isDead=false, bool isUndef=false, bool isEarlyClobber=false, unsigned SubReg=0, bool isDebug=false, bool isInternalRead=false, bool isRenamable=false)
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI bool hasOneNonDBGUse(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug use of the specified register.
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual register.
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
LLVM_ABI const TargetRegisterClass * constrainRegClass(Register Reg, const TargetRegisterClass *RC, unsigned MinNumRegs=0)
constrainRegClass - Constrain the register class of the specified virtual register to be a common sub...
LLVM_ABI MachineInstr * getUniqueVRegDef(Register Reg) const
getUniqueVRegDef - Return the unique machine instr that defines the specified virtual register or nul...
void dump() const
Definition Pass.cpp:146
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
Definition Analysis.h:151
Wrapper class representing virtual and physical registers.
Definition Register.h:20
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
Definition Register.h:83
static bool isFLATScratch(const MachineInstr &MI)
static bool isVIMAGE(const MachineInstr &MI)
static bool isFLATGlobal(const MachineInstr &MI)
static bool isVSAMPLE(const MachineInstr &MI)
static bool isFLAT(const MachineInstr &MI)
LLVM_READONLY MachineOperand * getNamedOperand(MachineInstr &MI, AMDGPU::OpName OperandName) const
Returns the operand named Op.
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
bool isLegalFlatAddressingMode(const AddrMode &AM, unsigned AddrSpace) const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
reference emplace_back(ArgTypes &&... Args)
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
std::pair< iterator, bool > insert(const ValueT &V)
Definition DenseSet.h:209
bool contains(const_arg_type_t< ValueT > V) const
Check if the set contains the given element.
Definition DenseSet.h:182
Changed
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Abstract Attribute helper functions.
Definition Attributor.h:165
@ FLAT_ADDRESS
Address space for flat memory.
@ GLOBAL_ADDRESS
Address space for global memory (RAT0, VTX0).
LLVM_READONLY const MIMGInfo * getMIMGInfo(unsigned Opc)
uint64_t convertSMRDOffsetUnits(const MCSubtargetInfo &ST, uint64_t ByteOffset)
Convert ByteOffset to dwords if the subtarget uses dword SMRD immediate offsets.
bool getMTBUFHasSrsrc(unsigned Opc)
int getMTBUFElements(unsigned Opc)
bool getMTBUFHasSoffset(unsigned Opc)
int getMUBUFOpcode(unsigned BaseOpc, unsigned Elements)
int getMUBUFBaseOpcode(unsigned Opc)
LLVM_READONLY bool hasNamedOperand(uint64_t Opcode, OpName NamedIdx)
int getMTBUFBaseOpcode(unsigned Opc)
bool getMUBUFHasVAddr(unsigned Opc)
int getMTBUFOpcode(unsigned BaseOpc, unsigned Elements)
bool getMUBUFHasSoffset(unsigned Opc)
const MIMGBaseOpcodeInfo * getMIMGBaseOpcode(unsigned Opc)
LLVM_READONLY const MIMGBaseOpcodeInfo * getMIMGBaseOpcodeInfo(unsigned BaseOpcode)
int getMaskedMIMGOp(unsigned Opc, unsigned NewChannels)
bool getMTBUFHasVAddr(unsigned Opc)
int getMUBUFElements(unsigned Opc)
const GcnBufferFormatInfo * getGcnBufferFormatInfo(uint8_t BitsPerComp, uint8_t NumComponents, uint8_t NumFormat, const MCSubtargetInfo &STI)
bool getMUBUFHasSrsrc(unsigned Opc)
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
NodeAddr< DefNode * > Def
Definition RDFGraph.h:384
BaseReg
Stack frame base register. Bit 0 of FREInfo.Info.
Definition SFrame.h:77
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:578
bool operator<(int64_t V1, const APSInt &V2)
Definition APSInt.h:360
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
RegState
Flags to represent properties of register accesses.
constexpr T maskLeadingOnes(unsigned N)
Create a bitmask with the N left-most bits set to 1, and all other bits set to 0.
Definition MathExtras.h:89
FunctionPass * createSILoadStoreOptimizerLegacyPass()
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
char & SILoadStoreOptimizerLegacyID
constexpr int popcount(T Value) noexcept
Count the number of set bits in a value.
Definition bit.h:156
int countr_zero(T Val)
Count number of 0's from the least significant bit to the most stopping at the first 1.
Definition bit.h:204
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
int countl_zero(T Val)
Count number of 0's from the most significant bit to the least stopping at the first 1.
Definition bit.h:263
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
Definition MathExtras.h:190
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
@ Other
Any other memory.
Definition ModRef.h:68
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
Definition ModRef.h:74
DWARFExpression::Operation Op
std::vector< std::pair< LineLocation, FunctionId > > AnchorList
constexpr unsigned BitWidth
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Next
Definition InstrProf.h:147
constexpr T maskTrailingOnes(unsigned N)
Create a bitmask with the N right-most bits set to 1, and all other bits set to 0.
Definition MathExtras.h:78
AAResults AliasAnalysis
Temporary typedef for legacy code that uses a generic AliasAnalysis pointer or reference.
LLVM_ABI Printable printReg(Register Reg, const TargetRegisterInfo *TRI=nullptr, unsigned SubIdx=0, const MachineRegisterInfo *MRI=nullptr)
Prints virtual and physical registers with or without a TRI instance.
MCRegisterClass TargetRegisterClass
Definition FastISel.h:58
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:880