blob: d42000b87c5b11094e8f97a120180c06fe99b21d [file] [log] [blame]
Eugene Zelenkoc8fbf6f2017-08-10 00:46:15 +00001//===- SIMemoryLegalizer.cpp ----------------------------------------------===//
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10/// \file
11/// \brief Memory legalizer - implements memory model. More information can be
12/// found here:
13/// http://llvm.org/docs/AMDGPUUsage.html#memory-model
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +000014//
15//===----------------------------------------------------------------------===//
16
17#include "AMDGPU.h"
18#include "AMDGPUMachineModuleInfo.h"
19#include "AMDGPUSubtarget.h"
Eugene Zelenkoc8fbf6f2017-08-10 00:46:15 +000020#include "SIDefines.h"
21#include "SIInstrInfo.h"
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +000022#include "Utils/AMDGPUBaseInfo.h"
Eugene Zelenkoc8fbf6f2017-08-10 00:46:15 +000023#include "llvm/ADT/None.h"
24#include "llvm/ADT/Optional.h"
25#include "llvm/CodeGen/MachineBasicBlock.h"
26#include "llvm/CodeGen/MachineFunction.h"
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +000027#include "llvm/CodeGen/MachineFunctionPass.h"
28#include "llvm/CodeGen/MachineInstrBuilder.h"
Eugene Zelenkoc8fbf6f2017-08-10 00:46:15 +000029#include "llvm/CodeGen/MachineMemOperand.h"
30#include "llvm/CodeGen/MachineModuleInfo.h"
31#include "llvm/CodeGen/MachineOperand.h"
32#include "llvm/IR/DebugLoc.h"
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +000033#include "llvm/IR/DiagnosticInfo.h"
Eugene Zelenkoc8fbf6f2017-08-10 00:46:15 +000034#include "llvm/IR/Function.h"
35#include "llvm/IR/LLVMContext.h"
36#include "llvm/MC/MCInstrDesc.h"
37#include "llvm/Pass.h"
38#include "llvm/Support/AtomicOrdering.h"
39#include <cassert>
40#include <list>
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +000041
42using namespace llvm;
43using namespace llvm::AMDGPU;
44
45#define DEBUG_TYPE "si-memory-legalizer"
46#define PASS_NAME "SI Memory Legalizer"
47
48namespace {
49
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +000050class SIMemOpInfo final {
51private:
Konstantin Zhuravlyov844845a2017-09-05 16:18:05 +000052 SyncScope::ID SSID = SyncScope::System;
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +000053 AtomicOrdering Ordering = AtomicOrdering::NotAtomic;
54 AtomicOrdering FailureOrdering = AtomicOrdering::NotAtomic;
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +000055
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +000056 SIMemOpInfo(SyncScope::ID SSID, AtomicOrdering Ordering)
57 : SSID(SSID), Ordering(Ordering) {}
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +000058
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +000059 SIMemOpInfo(SyncScope::ID SSID, AtomicOrdering Ordering,
Konstantin Zhuravlyovf5d826a2017-08-18 17:30:02 +000060 AtomicOrdering FailureOrdering)
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +000061 : SSID(SSID), Ordering(Ordering), FailureOrdering(FailureOrdering) {}
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +000062
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +000063 /// \returns Info constructed from \p MI, which has at least machine memory
64 /// operand.
65 static Optional<SIMemOpInfo> constructFromMIWithMMO(
66 const MachineBasicBlock::iterator &MI);
67
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +000068public:
69 /// \returns Synchronization scope ID of the machine instruction used to
70 /// create this SIMemOpInfo.
71 SyncScope::ID getSSID() const {
72 return SSID;
73 }
74 /// \returns Ordering constraint of the machine instruction used to
75 /// create this SIMemOpInfo.
76 AtomicOrdering getOrdering() const {
77 return Ordering;
78 }
79 /// \returns Failure ordering constraint of the machine instruction used to
80 /// create this SIMemOpInfo.
81 AtomicOrdering getFailureOrdering() const {
82 return FailureOrdering;
83 }
84
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +000085 /// \returns True if ordering constraint of the machine instruction used to
86 /// create this SIMemOpInfo is unordered or higher, false otherwise.
87 bool isAtomic() const {
88 return Ordering != AtomicOrdering::NotAtomic;
89 }
90
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +000091 /// \returns Load info if \p MI is a load operation, "None" otherwise.
92 static Optional<SIMemOpInfo> getLoadInfo(
93 const MachineBasicBlock::iterator &MI);
94 /// \returns Store info if \p MI is a store operation, "None" otherwise.
95 static Optional<SIMemOpInfo> getStoreInfo(
96 const MachineBasicBlock::iterator &MI);
97 /// \returns Atomic fence info if \p MI is an atomic fence operation,
98 /// "None" otherwise.
99 static Optional<SIMemOpInfo> getAtomicFenceInfo(
100 const MachineBasicBlock::iterator &MI);
101 /// \returns Atomic cmpxchg info if \p MI is an atomic cmpxchg operation,
102 /// "None" otherwise.
103 static Optional<SIMemOpInfo> getAtomicCmpxchgInfo(
104 const MachineBasicBlock::iterator &MI);
105 /// \returns Atomic rmw info if \p MI is an atomic rmw operation,
106 /// "None" otherwise.
107 static Optional<SIMemOpInfo> getAtomicRmwInfo(
108 const MachineBasicBlock::iterator &MI);
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000109
110 /// \brief Reports unknown synchronization scope used in \p MI to LLVM
111 /// context.
112 static void reportUnknownSyncScope(
113 const MachineBasicBlock::iterator &MI);
Konstantin Zhuravlyov844845a2017-09-05 16:18:05 +0000114};
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000115
Konstantin Zhuravlyov844845a2017-09-05 16:18:05 +0000116class SIMemoryLegalizer final : public MachineFunctionPass {
117private:
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000118 /// \brief Machine module info.
119 const AMDGPUMachineModuleInfo *MMI = nullptr;
Eugene Zelenkoc8fbf6f2017-08-10 00:46:15 +0000120
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000121 /// \brief Instruction info.
122 const SIInstrInfo *TII = nullptr;
123
124 /// \brief Immediate for "vmcnt(0)".
125 unsigned Vmcnt0Immediate = 0;
Eugene Zelenkoc8fbf6f2017-08-10 00:46:15 +0000126
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000127 /// \brief Opcode for cache invalidation instruction (L1).
128 unsigned Wbinvl1Opcode = 0;
129
130 /// \brief List of atomic pseudo instructions.
131 std::list<MachineBasicBlock::iterator> AtomicPseudoMIs;
132
133 /// \brief Inserts "buffer_wbinvl1_vol" instruction \p Before or after \p MI.
134 /// Always returns true.
135 bool insertBufferWbinvl1Vol(MachineBasicBlock::iterator &MI,
136 bool Before = true) const;
137 /// \brief Inserts "s_waitcnt vmcnt(0)" instruction \p Before or after \p MI.
138 /// Always returns true.
139 bool insertWaitcntVmcnt0(MachineBasicBlock::iterator &MI,
140 bool Before = true) const;
141
142 /// \brief Sets GLC bit if present in \p MI. Returns true if \p MI is
143 /// modified, false otherwise.
144 bool setGLC(const MachineBasicBlock::iterator &MI) const;
145
146 /// \brief Removes all processed atomic pseudo instructions from the current
147 /// function. Returns true if current function is modified, false otherwise.
148 bool removeAtomicPseudoMIs();
149
Konstantin Zhuravlyovf5d826a2017-08-18 17:30:02 +0000150 /// \brief Expands load operation \p MI. Returns true if instructions are
151 /// added/deleted or \p MI is modified, false otherwise.
Konstantin Zhuravlyov844845a2017-09-05 16:18:05 +0000152 bool expandLoad(const SIMemOpInfo &MOI,
153 MachineBasicBlock::iterator &MI);
Konstantin Zhuravlyovf5d826a2017-08-18 17:30:02 +0000154 /// \brief Expands store operation \p MI. Returns true if instructions are
155 /// added/deleted or \p MI is modified, false otherwise.
Konstantin Zhuravlyov844845a2017-09-05 16:18:05 +0000156 bool expandStore(const SIMemOpInfo &MOI,
157 MachineBasicBlock::iterator &MI);
Konstantin Zhuravlyov89377c42017-08-19 18:44:27 +0000158 /// \brief Expands atomic fence operation \p MI. Returns true if
159 /// instructions are added/deleted or \p MI is modified, false otherwise.
Konstantin Zhuravlyov844845a2017-09-05 16:18:05 +0000160 bool expandAtomicFence(const SIMemOpInfo &MOI,
Konstantin Zhuravlyov89377c42017-08-19 18:44:27 +0000161 MachineBasicBlock::iterator &MI);
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000162 /// \brief Expands atomic cmpxchg operation \p MI. Returns true if
163 /// instructions are added/deleted or \p MI is modified, false otherwise.
Konstantin Zhuravlyov844845a2017-09-05 16:18:05 +0000164 bool expandAtomicCmpxchg(const SIMemOpInfo &MOI,
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000165 MachineBasicBlock::iterator &MI);
166 /// \brief Expands atomic rmw operation \p MI. Returns true if
167 /// instructions are added/deleted or \p MI is modified, false otherwise.
Konstantin Zhuravlyov844845a2017-09-05 16:18:05 +0000168 bool expandAtomicRmw(const SIMemOpInfo &MOI,
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000169 MachineBasicBlock::iterator &MI);
170
171public:
172 static char ID;
173
Eugene Zelenkoc8fbf6f2017-08-10 00:46:15 +0000174 SIMemoryLegalizer() : MachineFunctionPass(ID) {}
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000175
176 void getAnalysisUsage(AnalysisUsage &AU) const override {
177 AU.setPreservesCFG();
178 MachineFunctionPass::getAnalysisUsage(AU);
179 }
180
181 StringRef getPassName() const override {
182 return PASS_NAME;
183 }
184
185 bool runOnMachineFunction(MachineFunction &MF) override;
186};
187
188} // end namespace anonymous
189
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +0000190/* static */
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000191Optional<SIMemOpInfo> SIMemOpInfo::constructFromMIWithMMO(
192 const MachineBasicBlock::iterator &MI) {
193 assert(MI->getNumMemOperands() > 0);
194
195 const MachineFunction *MF = MI->getParent()->getParent();
196 const AMDGPUMachineModuleInfo *MMI =
197 &MF->getMMI().getObjFileInfo<AMDGPUMachineModuleInfo>();
198
199 SyncScope::ID SSID = SyncScope::SingleThread;
200 AtomicOrdering Ordering = AtomicOrdering::NotAtomic;
201 AtomicOrdering FailureOrdering = AtomicOrdering::NotAtomic;
202
203 // Validator should check whether or not MMOs cover the entire set of
204 // locations accessed by the memory instruction.
205 for (const auto &MMO : MI->memoperands()) {
206 const auto &IsSyncScopeInclusion =
207 MMI->isSyncScopeInclusion(SSID, MMO->getSyncScopeID());
208 if (!IsSyncScopeInclusion) {
209 reportUnknownSyncScope(MI);
210 return None;
211 }
212
213 SSID = IsSyncScopeInclusion.getValue() ? SSID : MMO->getSyncScopeID();
214 Ordering =
215 isStrongerThan(Ordering, MMO->getOrdering()) ?
216 Ordering : MMO->getOrdering();
217 FailureOrdering =
218 isStrongerThan(FailureOrdering, MMO->getFailureOrdering()) ?
219 FailureOrdering : MMO->getFailureOrdering();
220 }
221
222 return SIMemOpInfo(SSID, Ordering, FailureOrdering);
223}
224
225/* static */
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +0000226Optional<SIMemOpInfo> SIMemOpInfo::getLoadInfo(
227 const MachineBasicBlock::iterator &MI) {
228 assert(MI->getDesc().TSFlags & SIInstrFlags::maybeAtomic);
229
230 if (!(MI->mayLoad() && !MI->mayStore()))
231 return None;
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000232
233 // Be conservative if there are no memory operands.
234 if (MI->getNumMemOperands() == 0)
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000235 return SIMemOpInfo(SyncScope::System,
236 AtomicOrdering::SequentiallyConsistent);
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +0000237
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000238 return SIMemOpInfo::constructFromMIWithMMO(MI);
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +0000239}
240
241/* static */
242Optional<SIMemOpInfo> SIMemOpInfo::getStoreInfo(
243 const MachineBasicBlock::iterator &MI) {
244 assert(MI->getDesc().TSFlags & SIInstrFlags::maybeAtomic);
245
246 if (!(!MI->mayLoad() && MI->mayStore()))
247 return None;
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000248
249 // Be conservative if there are no memory operands.
250 if (MI->getNumMemOperands() == 0)
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000251 return SIMemOpInfo(SyncScope::System,
252 AtomicOrdering::SequentiallyConsistent);
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +0000253
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000254 return SIMemOpInfo::constructFromMIWithMMO(MI);
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +0000255}
256
257/* static */
258Optional<SIMemOpInfo> SIMemOpInfo::getAtomicFenceInfo(
259 const MachineBasicBlock::iterator &MI) {
260 assert(MI->getDesc().TSFlags & SIInstrFlags::maybeAtomic);
261
262 if (MI->getOpcode() != AMDGPU::ATOMIC_FENCE)
263 return None;
264
265 SyncScope::ID SSID =
266 static_cast<SyncScope::ID>(MI->getOperand(1).getImm());
267 AtomicOrdering Ordering =
268 static_cast<AtomicOrdering>(MI->getOperand(0).getImm());
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000269 return SIMemOpInfo(SSID, Ordering);
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +0000270}
271
272/* static */
273Optional<SIMemOpInfo> SIMemOpInfo::getAtomicCmpxchgInfo(
274 const MachineBasicBlock::iterator &MI) {
275 assert(MI->getDesc().TSFlags & SIInstrFlags::maybeAtomic);
276
277 if (!(MI->mayLoad() && MI->mayStore()))
278 return None;
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000279
280 // Be conservative if there are no memory operands.
281 if (MI->getNumMemOperands() == 0)
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000282 return SIMemOpInfo(SyncScope::System,
283 AtomicOrdering::SequentiallyConsistent,
284 AtomicOrdering::SequentiallyConsistent);
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +0000285
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000286 return SIMemOpInfo::constructFromMIWithMMO(MI);
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +0000287}
288
289/* static */
290Optional<SIMemOpInfo> SIMemOpInfo::getAtomicRmwInfo(
291 const MachineBasicBlock::iterator &MI) {
292 assert(MI->getDesc().TSFlags & SIInstrFlags::maybeAtomic);
293
294 if (!(MI->mayLoad() && MI->mayStore()))
295 return None;
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000296
297 // Be conservative if there are no memory operands.
298 if (MI->getNumMemOperands() == 0)
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000299 return SIMemOpInfo(SyncScope::System,
300 AtomicOrdering::SequentiallyConsistent);
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +0000301
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000302 return SIMemOpInfo::constructFromMIWithMMO(MI);
303}
304
305/* static */
306void SIMemOpInfo::reportUnknownSyncScope(
307 const MachineBasicBlock::iterator &MI) {
308 DiagnosticInfoUnsupported Diag(*MI->getParent()->getParent()->getFunction(),
309 "Unsupported synchronization scope");
310 LLVMContext *CTX = &MI->getParent()->getParent()->getFunction()->getContext();
311 CTX->diagnose(Diag);
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +0000312}
313
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000314bool SIMemoryLegalizer::insertBufferWbinvl1Vol(MachineBasicBlock::iterator &MI,
315 bool Before) const {
316 MachineBasicBlock &MBB = *MI->getParent();
317 DebugLoc DL = MI->getDebugLoc();
318
319 if (!Before)
320 ++MI;
321
322 BuildMI(MBB, MI, DL, TII->get(Wbinvl1Opcode));
323
324 if (!Before)
325 --MI;
326
327 return true;
328}
329
330bool SIMemoryLegalizer::insertWaitcntVmcnt0(MachineBasicBlock::iterator &MI,
331 bool Before) const {
332 MachineBasicBlock &MBB = *MI->getParent();
333 DebugLoc DL = MI->getDebugLoc();
334
335 if (!Before)
336 ++MI;
337
338 BuildMI(MBB, MI, DL, TII->get(AMDGPU::S_WAITCNT)).addImm(Vmcnt0Immediate);
339
340 if (!Before)
341 --MI;
342
343 return true;
344}
345
346bool SIMemoryLegalizer::setGLC(const MachineBasicBlock::iterator &MI) const {
347 int GLCIdx = AMDGPU::getNamedOperandIdx(MI->getOpcode(), AMDGPU::OpName::glc);
348 if (GLCIdx == -1)
349 return false;
350
351 MachineOperand &GLC = MI->getOperand(GLCIdx);
352 if (GLC.getImm() == 1)
353 return false;
354
355 GLC.setImm(1);
356 return true;
357}
358
359bool SIMemoryLegalizer::removeAtomicPseudoMIs() {
360 if (AtomicPseudoMIs.empty())
361 return false;
362
363 for (auto &MI : AtomicPseudoMIs)
364 MI->eraseFromParent();
365
366 AtomicPseudoMIs.clear();
367 return true;
368}
369
Konstantin Zhuravlyov844845a2017-09-05 16:18:05 +0000370bool SIMemoryLegalizer::expandLoad(const SIMemOpInfo &MOI,
Konstantin Zhuravlyovf5d826a2017-08-18 17:30:02 +0000371 MachineBasicBlock::iterator &MI) {
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000372 assert(MI->mayLoad() && !MI->mayStore());
373
374 bool Changed = false;
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000375
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000376 if (MOI.isAtomic()) {
377 if (MOI.getSSID() == SyncScope::System ||
378 MOI.getSSID() == MMI->getAgentSSID()) {
379 if (MOI.getOrdering() == AtomicOrdering::Acquire ||
380 MOI.getOrdering() == AtomicOrdering::SequentiallyConsistent)
381 Changed |= setGLC(MI);
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000382
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000383 if (MOI.getOrdering() == AtomicOrdering::SequentiallyConsistent)
384 Changed |= insertWaitcntVmcnt0(MI);
385
386 if (MOI.getOrdering() == AtomicOrdering::Acquire ||
387 MOI.getOrdering() == AtomicOrdering::SequentiallyConsistent) {
388 Changed |= insertWaitcntVmcnt0(MI, false);
389 Changed |= insertBufferWbinvl1Vol(MI, false);
390 }
391
392 return Changed;
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000393 }
394
395 if (MOI.getSSID() == SyncScope::SingleThread ||
396 MOI.getSSID() == MMI->getWorkgroupSSID() ||
397 MOI.getSSID() == MMI->getWavefrontSSID()) {
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000398 return Changed;
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000399 }
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000400
401 llvm_unreachable("Unsupported synchronization scope");
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000402 }
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000403
404 return Changed;
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000405}
406
Konstantin Zhuravlyov844845a2017-09-05 16:18:05 +0000407bool SIMemoryLegalizer::expandStore(const SIMemOpInfo &MOI,
Konstantin Zhuravlyovf5d826a2017-08-18 17:30:02 +0000408 MachineBasicBlock::iterator &MI) {
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000409 assert(!MI->mayLoad() && MI->mayStore());
410
411 bool Changed = false;
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000412
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000413 if (MOI.isAtomic()) {
414 if (MOI.getSSID() == SyncScope::System ||
415 MOI.getSSID() == MMI->getAgentSSID()) {
416 if (MOI.getOrdering() == AtomicOrdering::Release ||
417 MOI.getOrdering() == AtomicOrdering::SequentiallyConsistent)
418 Changed |= insertWaitcntVmcnt0(MI);
419
420 return Changed;
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000421 }
422
423 if (MOI.getSSID() == SyncScope::SingleThread ||
424 MOI.getSSID() == MMI->getWorkgroupSSID() ||
425 MOI.getSSID() == MMI->getWavefrontSSID()) {
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000426 return Changed;
427 }
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000428
429 llvm_unreachable("Unsupported synchronization scope");
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000430 }
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000431
432 return Changed;
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000433}
434
Konstantin Zhuravlyov844845a2017-09-05 16:18:05 +0000435bool SIMemoryLegalizer::expandAtomicFence(const SIMemOpInfo &MOI,
Konstantin Zhuravlyov89377c42017-08-19 18:44:27 +0000436 MachineBasicBlock::iterator &MI) {
437 assert(MI->getOpcode() == AMDGPU::ATOMIC_FENCE);
438
439 bool Changed = false;
Konstantin Zhuravlyov89377c42017-08-19 18:44:27 +0000440
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000441 if (MOI.isAtomic()) {
442 if (MOI.getSSID() == SyncScope::System ||
443 MOI.getSSID() == MMI->getAgentSSID()) {
444 if (MOI.getOrdering() == AtomicOrdering::Acquire ||
445 MOI.getOrdering() == AtomicOrdering::Release ||
446 MOI.getOrdering() == AtomicOrdering::AcquireRelease ||
447 MOI.getOrdering() == AtomicOrdering::SequentiallyConsistent)
448 Changed |= insertWaitcntVmcnt0(MI);
Konstantin Zhuravlyov89377c42017-08-19 18:44:27 +0000449
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000450 if (MOI.getOrdering() == AtomicOrdering::Acquire ||
451 MOI.getOrdering() == AtomicOrdering::AcquireRelease ||
452 MOI.getOrdering() == AtomicOrdering::SequentiallyConsistent)
453 Changed |= insertBufferWbinvl1Vol(MI);
454
455 AtomicPseudoMIs.push_back(MI);
456 return Changed;
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000457 }
458
459 if (MOI.getSSID() == SyncScope::SingleThread ||
460 MOI.getSSID() == MMI->getWorkgroupSSID() ||
461 MOI.getSSID() == MMI->getWavefrontSSID()) {
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000462 AtomicPseudoMIs.push_back(MI);
463 return Changed;
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000464 }
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000465
466 SIMemOpInfo::reportUnknownSyncScope(MI);
Konstantin Zhuravlyov89377c42017-08-19 18:44:27 +0000467 }
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000468
469 return Changed;
Konstantin Zhuravlyov89377c42017-08-19 18:44:27 +0000470}
471
Konstantin Zhuravlyov844845a2017-09-05 16:18:05 +0000472bool SIMemoryLegalizer::expandAtomicCmpxchg(const SIMemOpInfo &MOI,
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000473 MachineBasicBlock::iterator &MI) {
474 assert(MI->mayLoad() && MI->mayStore());
475
476 bool Changed = false;
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000477
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000478 if (MOI.isAtomic()) {
479 if (MOI.getSSID() == SyncScope::System ||
480 MOI.getSSID() == MMI->getAgentSSID()) {
481 if (MOI.getOrdering() == AtomicOrdering::Release ||
482 MOI.getOrdering() == AtomicOrdering::AcquireRelease ||
483 MOI.getOrdering() == AtomicOrdering::SequentiallyConsistent ||
484 MOI.getFailureOrdering() == AtomicOrdering::SequentiallyConsistent)
485 Changed |= insertWaitcntVmcnt0(MI);
486
487 if (MOI.getOrdering() == AtomicOrdering::Acquire ||
488 MOI.getOrdering() == AtomicOrdering::AcquireRelease ||
489 MOI.getOrdering() == AtomicOrdering::SequentiallyConsistent ||
490 MOI.getFailureOrdering() == AtomicOrdering::Acquire ||
491 MOI.getFailureOrdering() == AtomicOrdering::SequentiallyConsistent) {
492 Changed |= insertWaitcntVmcnt0(MI, false);
493 Changed |= insertBufferWbinvl1Vol(MI, false);
494 }
495
496 return Changed;
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000497 }
498
499 if (MOI.getSSID() == SyncScope::SingleThread ||
500 MOI.getSSID() == MMI->getWorkgroupSSID() ||
501 MOI.getSSID() == MMI->getWavefrontSSID()) {
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000502 Changed |= setGLC(MI);
503 return Changed;
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000504 }
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000505
506 llvm_unreachable("Unsupported synchronization scope");
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000507 }
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000508
509 return Changed;
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000510}
511
Konstantin Zhuravlyov844845a2017-09-05 16:18:05 +0000512bool SIMemoryLegalizer::expandAtomicRmw(const SIMemOpInfo &MOI,
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000513 MachineBasicBlock::iterator &MI) {
514 assert(MI->mayLoad() && MI->mayStore());
515
516 bool Changed = false;
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000517
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000518 if (MOI.isAtomic()) {
519 if (MOI.getSSID() == SyncScope::System ||
520 MOI.getSSID() == MMI->getAgentSSID()) {
521 if (MOI.getOrdering() == AtomicOrdering::Release ||
522 MOI.getOrdering() == AtomicOrdering::AcquireRelease ||
523 MOI.getOrdering() == AtomicOrdering::SequentiallyConsistent)
524 Changed |= insertWaitcntVmcnt0(MI);
525
526 if (MOI.getOrdering() == AtomicOrdering::Acquire ||
527 MOI.getOrdering() == AtomicOrdering::AcquireRelease ||
528 MOI.getOrdering() == AtomicOrdering::SequentiallyConsistent) {
529 Changed |= insertWaitcntVmcnt0(MI, false);
530 Changed |= insertBufferWbinvl1Vol(MI, false);
531 }
532
533 return Changed;
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000534 }
535
536 if (MOI.getSSID() == SyncScope::SingleThread ||
537 MOI.getSSID() == MMI->getWorkgroupSSID() ||
538 MOI.getSSID() == MMI->getWavefrontSSID()) {
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000539 Changed |= setGLC(MI);
540 return Changed;
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000541 }
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000542
543 llvm_unreachable("Unsupported synchronization scope");
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000544 }
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000545
546 return Changed;
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000547}
548
549bool SIMemoryLegalizer::runOnMachineFunction(MachineFunction &MF) {
550 bool Changed = false;
551 const SISubtarget &ST = MF.getSubtarget<SISubtarget>();
552 const IsaInfo::IsaVersion IV = IsaInfo::getIsaVersion(ST.getFeatureBits());
553
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000554 MMI = &MF.getMMI().getObjFileInfo<AMDGPUMachineModuleInfo>();
555 TII = ST.getInstrInfo();
556
557 Vmcnt0Immediate =
558 AMDGPU::encodeWaitcnt(IV, 0, getExpcntBitMask(IV), getLgkmcntBitMask(IV));
559 Wbinvl1Opcode = ST.getGeneration() <= AMDGPUSubtarget::SOUTHERN_ISLANDS ?
560 AMDGPU::BUFFER_WBINVL1 : AMDGPU::BUFFER_WBINVL1_VOL;
561
562 for (auto &MBB : MF) {
563 for (auto MI = MBB.begin(); MI != MBB.end(); ++MI) {
564 if (!(MI->getDesc().TSFlags & SIInstrFlags::maybeAtomic))
565 continue;
566
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +0000567 if (const auto &MOI = SIMemOpInfo::getLoadInfo(MI))
Konstantin Zhuravlyovf5d826a2017-08-18 17:30:02 +0000568 Changed |= expandLoad(MOI.getValue(), MI);
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +0000569 else if (const auto &MOI = SIMemOpInfo::getStoreInfo(MI))
Konstantin Zhuravlyovf5d826a2017-08-18 17:30:02 +0000570 Changed |= expandStore(MOI.getValue(), MI);
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +0000571 else if (const auto &MOI = SIMemOpInfo::getAtomicFenceInfo(MI))
Konstantin Zhuravlyov89377c42017-08-19 18:44:27 +0000572 Changed |= expandAtomicFence(MOI.getValue(), MI);
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +0000573 else if (const auto &MOI = SIMemOpInfo::getAtomicCmpxchgInfo(MI))
Konstantin Zhuravlyovf5d826a2017-08-18 17:30:02 +0000574 Changed |= expandAtomicCmpxchg(MOI.getValue(), MI);
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +0000575 else if (const auto &MOI = SIMemOpInfo::getAtomicRmwInfo(MI))
Konstantin Zhuravlyovf5d826a2017-08-18 17:30:02 +0000576 Changed |= expandAtomicRmw(MOI.getValue(), MI);
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000577 }
578 }
579
580 Changed |= removeAtomicPseudoMIs();
581 return Changed;
582}
583
584INITIALIZE_PASS(SIMemoryLegalizer, DEBUG_TYPE, PASS_NAME, false, false)
585
586char SIMemoryLegalizer::ID = 0;
587char &llvm::SIMemoryLegalizerID = SIMemoryLegalizer::ID;
588
589FunctionPass *llvm::createSIMemoryLegalizerPass() {
590 return new SIMemoryLegalizer();
591}