blob: 5f4636e12d702c7f7c20050fe5f977107c8fad18 [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 Zhuravlyov5f5b5862017-09-07 17:14:54 +000055 bool IsNonTemporal = false;
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +000056
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +000057 SIMemOpInfo(SyncScope::ID SSID, AtomicOrdering Ordering)
58 : SSID(SSID), Ordering(Ordering) {}
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +000059
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +000060 SIMemOpInfo(SyncScope::ID SSID, AtomicOrdering Ordering,
Konstantin Zhuravlyov5f5b5862017-09-07 17:14:54 +000061 AtomicOrdering FailureOrdering, bool IsNonTemporal = false)
62 : SSID(SSID), Ordering(Ordering), FailureOrdering(FailureOrdering),
63 IsNonTemporal(IsNonTemporal) {}
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +000064
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +000065 /// \returns Info constructed from \p MI, which has at least machine memory
66 /// operand.
67 static Optional<SIMemOpInfo> constructFromMIWithMMO(
68 const MachineBasicBlock::iterator &MI);
69
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +000070public:
71 /// \returns Synchronization scope ID of the machine instruction used to
72 /// create this SIMemOpInfo.
73 SyncScope::ID getSSID() const {
74 return SSID;
75 }
76 /// \returns Ordering constraint of the machine instruction used to
77 /// create this SIMemOpInfo.
78 AtomicOrdering getOrdering() const {
79 return Ordering;
80 }
81 /// \returns Failure ordering constraint of the machine instruction used to
82 /// create this SIMemOpInfo.
83 AtomicOrdering getFailureOrdering() const {
84 return FailureOrdering;
85 }
Konstantin Zhuravlyov5f5b5862017-09-07 17:14:54 +000086 /// \returns True if memory access of the machine instruction used to
87 /// create this SIMemOpInfo is non-temporal, false otherwise.
88 bool isNonTemporal() const {
89 return IsNonTemporal;
90 }
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +000091
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +000092 /// \returns True if ordering constraint of the machine instruction used to
93 /// create this SIMemOpInfo is unordered or higher, false otherwise.
94 bool isAtomic() const {
95 return Ordering != AtomicOrdering::NotAtomic;
96 }
97
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +000098 /// \returns Load info if \p MI is a load operation, "None" otherwise.
99 static Optional<SIMemOpInfo> getLoadInfo(
100 const MachineBasicBlock::iterator &MI);
101 /// \returns Store info if \p MI is a store operation, "None" otherwise.
102 static Optional<SIMemOpInfo> getStoreInfo(
103 const MachineBasicBlock::iterator &MI);
104 /// \returns Atomic fence info if \p MI is an atomic fence operation,
105 /// "None" otherwise.
106 static Optional<SIMemOpInfo> getAtomicFenceInfo(
107 const MachineBasicBlock::iterator &MI);
Stanislav Mekhanoshince2d428a2018-02-06 19:11:56 +0000108 /// \returns Atomic cmpxchg/rmw info if \p MI is an atomic cmpxchg or
109 /// rmw operation, "None" otherwise.
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +0000110 static Optional<SIMemOpInfo> getAtomicCmpxchgInfo(
111 const MachineBasicBlock::iterator &MI);
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000112
113 /// \brief Reports unknown synchronization scope used in \p MI to LLVM
114 /// context.
115 static void reportUnknownSyncScope(
116 const MachineBasicBlock::iterator &MI);
Konstantin Zhuravlyov844845a2017-09-05 16:18:05 +0000117};
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000118
Konstantin Zhuravlyov844845a2017-09-05 16:18:05 +0000119class SIMemoryLegalizer final : public MachineFunctionPass {
120private:
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000121 /// \brief Machine module info.
122 const AMDGPUMachineModuleInfo *MMI = nullptr;
Eugene Zelenkoc8fbf6f2017-08-10 00:46:15 +0000123
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000124 /// \brief Instruction info.
125 const SIInstrInfo *TII = nullptr;
126
127 /// \brief Immediate for "vmcnt(0)".
128 unsigned Vmcnt0Immediate = 0;
Eugene Zelenkoc8fbf6f2017-08-10 00:46:15 +0000129
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000130 /// \brief Opcode for cache invalidation instruction (L1).
131 unsigned Wbinvl1Opcode = 0;
132
133 /// \brief List of atomic pseudo instructions.
134 std::list<MachineBasicBlock::iterator> AtomicPseudoMIs;
135
Konstantin Zhuravlyov5f5b5862017-09-07 17:14:54 +0000136 /// \brief Sets named bit (BitName) to "true" if present in \p MI. Returns
137 /// true if \p MI is modified, false otherwise.
138 template <uint16_t BitName>
139 bool enableNamedBit(const MachineBasicBlock::iterator &MI) const {
140 int BitIdx = AMDGPU::getNamedOperandIdx(MI->getOpcode(), BitName);
141 if (BitIdx == -1)
142 return false;
143
144 MachineOperand &Bit = MI->getOperand(BitIdx);
145 if (Bit.getImm() != 0)
146 return false;
147
148 Bit.setImm(1);
149 return true;
150 }
151
152 /// \brief Sets GLC bit to "true" if present in \p MI. Returns true if \p MI
153 /// is modified, false otherwise.
154 bool enableGLCBit(const MachineBasicBlock::iterator &MI) const {
155 return enableNamedBit<AMDGPU::OpName::glc>(MI);
156 }
157
158 /// \brief Sets SLC bit to "true" if present in \p MI. Returns true if \p MI
159 /// is modified, false otherwise.
160 bool enableSLCBit(const MachineBasicBlock::iterator &MI) const {
161 return enableNamedBit<AMDGPU::OpName::slc>(MI);
162 }
163
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000164 /// \brief Inserts "buffer_wbinvl1_vol" instruction \p Before or after \p MI.
165 /// Always returns true.
166 bool insertBufferWbinvl1Vol(MachineBasicBlock::iterator &MI,
167 bool Before = true) const;
168 /// \brief Inserts "s_waitcnt vmcnt(0)" instruction \p Before or after \p MI.
169 /// Always returns true.
170 bool insertWaitcntVmcnt0(MachineBasicBlock::iterator &MI,
171 bool Before = true) const;
172
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000173 /// \brief Removes all processed atomic pseudo instructions from the current
174 /// function. Returns true if current function is modified, false otherwise.
175 bool removeAtomicPseudoMIs();
176
Konstantin Zhuravlyovf5d826a2017-08-18 17:30:02 +0000177 /// \brief Expands load operation \p MI. Returns true if instructions are
178 /// added/deleted or \p MI is modified, false otherwise.
Konstantin Zhuravlyov844845a2017-09-05 16:18:05 +0000179 bool expandLoad(const SIMemOpInfo &MOI,
180 MachineBasicBlock::iterator &MI);
Konstantin Zhuravlyovf5d826a2017-08-18 17:30:02 +0000181 /// \brief Expands store operation \p MI. Returns true if instructions are
182 /// added/deleted or \p MI is modified, false otherwise.
Konstantin Zhuravlyov844845a2017-09-05 16:18:05 +0000183 bool expandStore(const SIMemOpInfo &MOI,
184 MachineBasicBlock::iterator &MI);
Konstantin Zhuravlyov89377c42017-08-19 18:44:27 +0000185 /// \brief Expands atomic fence operation \p MI. Returns true if
186 /// instructions are added/deleted or \p MI is modified, false otherwise.
Konstantin Zhuravlyov844845a2017-09-05 16:18:05 +0000187 bool expandAtomicFence(const SIMemOpInfo &MOI,
Konstantin Zhuravlyov89377c42017-08-19 18:44:27 +0000188 MachineBasicBlock::iterator &MI);
Stanislav Mekhanoshince2d428a2018-02-06 19:11:56 +0000189 /// \brief Expands atomic cmpxchg or rmw operation \p MI. Returns true if
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000190 /// instructions are added/deleted or \p MI is modified, false otherwise.
Konstantin Zhuravlyov844845a2017-09-05 16:18:05 +0000191 bool expandAtomicCmpxchg(const SIMemOpInfo &MOI,
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000192 MachineBasicBlock::iterator &MI);
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000193
194public:
195 static char ID;
196
Eugene Zelenkoc8fbf6f2017-08-10 00:46:15 +0000197 SIMemoryLegalizer() : MachineFunctionPass(ID) {}
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000198
199 void getAnalysisUsage(AnalysisUsage &AU) const override {
200 AU.setPreservesCFG();
201 MachineFunctionPass::getAnalysisUsage(AU);
202 }
203
204 StringRef getPassName() const override {
205 return PASS_NAME;
206 }
207
208 bool runOnMachineFunction(MachineFunction &MF) override;
209};
210
211} // end namespace anonymous
212
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +0000213/* static */
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000214Optional<SIMemOpInfo> SIMemOpInfo::constructFromMIWithMMO(
215 const MachineBasicBlock::iterator &MI) {
216 assert(MI->getNumMemOperands() > 0);
217
218 const MachineFunction *MF = MI->getParent()->getParent();
219 const AMDGPUMachineModuleInfo *MMI =
220 &MF->getMMI().getObjFileInfo<AMDGPUMachineModuleInfo>();
221
222 SyncScope::ID SSID = SyncScope::SingleThread;
223 AtomicOrdering Ordering = AtomicOrdering::NotAtomic;
224 AtomicOrdering FailureOrdering = AtomicOrdering::NotAtomic;
Konstantin Zhuravlyov5f5b5862017-09-07 17:14:54 +0000225 bool IsNonTemporal = true;
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000226
227 // Validator should check whether or not MMOs cover the entire set of
228 // locations accessed by the memory instruction.
229 for (const auto &MMO : MI->memoperands()) {
230 const auto &IsSyncScopeInclusion =
231 MMI->isSyncScopeInclusion(SSID, MMO->getSyncScopeID());
232 if (!IsSyncScopeInclusion) {
233 reportUnknownSyncScope(MI);
234 return None;
235 }
236
237 SSID = IsSyncScopeInclusion.getValue() ? SSID : MMO->getSyncScopeID();
238 Ordering =
239 isStrongerThan(Ordering, MMO->getOrdering()) ?
240 Ordering : MMO->getOrdering();
241 FailureOrdering =
242 isStrongerThan(FailureOrdering, MMO->getFailureOrdering()) ?
243 FailureOrdering : MMO->getFailureOrdering();
Konstantin Zhuravlyov5f5b5862017-09-07 17:14:54 +0000244
245 if (!(MMO->getFlags() & MachineMemOperand::MONonTemporal))
246 IsNonTemporal = false;
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000247 }
248
Konstantin Zhuravlyov5f5b5862017-09-07 17:14:54 +0000249 return SIMemOpInfo(SSID, Ordering, FailureOrdering, IsNonTemporal);
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000250}
251
252/* static */
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +0000253Optional<SIMemOpInfo> SIMemOpInfo::getLoadInfo(
254 const MachineBasicBlock::iterator &MI) {
255 assert(MI->getDesc().TSFlags & SIInstrFlags::maybeAtomic);
256
257 if (!(MI->mayLoad() && !MI->mayStore()))
258 return None;
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000259
260 // Be conservative if there are no memory operands.
261 if (MI->getNumMemOperands() == 0)
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000262 return SIMemOpInfo(SyncScope::System,
263 AtomicOrdering::SequentiallyConsistent);
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +0000264
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000265 return SIMemOpInfo::constructFromMIWithMMO(MI);
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +0000266}
267
268/* static */
269Optional<SIMemOpInfo> SIMemOpInfo::getStoreInfo(
270 const MachineBasicBlock::iterator &MI) {
271 assert(MI->getDesc().TSFlags & SIInstrFlags::maybeAtomic);
272
273 if (!(!MI->mayLoad() && MI->mayStore()))
274 return None;
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000275
276 // Be conservative if there are no memory operands.
277 if (MI->getNumMemOperands() == 0)
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000278 return SIMemOpInfo(SyncScope::System,
279 AtomicOrdering::SequentiallyConsistent);
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +0000280
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000281 return SIMemOpInfo::constructFromMIWithMMO(MI);
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +0000282}
283
284/* static */
285Optional<SIMemOpInfo> SIMemOpInfo::getAtomicFenceInfo(
286 const MachineBasicBlock::iterator &MI) {
287 assert(MI->getDesc().TSFlags & SIInstrFlags::maybeAtomic);
288
289 if (MI->getOpcode() != AMDGPU::ATOMIC_FENCE)
290 return None;
291
292 SyncScope::ID SSID =
293 static_cast<SyncScope::ID>(MI->getOperand(1).getImm());
294 AtomicOrdering Ordering =
295 static_cast<AtomicOrdering>(MI->getOperand(0).getImm());
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000296 return SIMemOpInfo(SSID, Ordering);
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +0000297}
298
299/* static */
300Optional<SIMemOpInfo> SIMemOpInfo::getAtomicCmpxchgInfo(
301 const MachineBasicBlock::iterator &MI) {
302 assert(MI->getDesc().TSFlags & SIInstrFlags::maybeAtomic);
303
304 if (!(MI->mayLoad() && MI->mayStore()))
305 return None;
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000306
307 // Be conservative if there are no memory operands.
308 if (MI->getNumMemOperands() == 0)
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000309 return SIMemOpInfo(SyncScope::System,
310 AtomicOrdering::SequentiallyConsistent,
311 AtomicOrdering::SequentiallyConsistent);
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +0000312
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000313 return SIMemOpInfo::constructFromMIWithMMO(MI);
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +0000314}
315
316/* static */
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000317void SIMemOpInfo::reportUnknownSyncScope(
318 const MachineBasicBlock::iterator &MI) {
Matthias Braunf1caa282017-12-15 22:22:58 +0000319 DiagnosticInfoUnsupported Diag(MI->getParent()->getParent()->getFunction(),
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000320 "Unsupported synchronization scope");
Matthias Braunf1caa282017-12-15 22:22:58 +0000321 LLVMContext *CTX = &MI->getParent()->getParent()->getFunction().getContext();
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000322 CTX->diagnose(Diag);
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +0000323}
324
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000325bool SIMemoryLegalizer::insertBufferWbinvl1Vol(MachineBasicBlock::iterator &MI,
326 bool Before) const {
327 MachineBasicBlock &MBB = *MI->getParent();
328 DebugLoc DL = MI->getDebugLoc();
329
330 if (!Before)
331 ++MI;
332
333 BuildMI(MBB, MI, DL, TII->get(Wbinvl1Opcode));
334
335 if (!Before)
336 --MI;
337
338 return true;
339}
340
341bool SIMemoryLegalizer::insertWaitcntVmcnt0(MachineBasicBlock::iterator &MI,
342 bool Before) const {
343 MachineBasicBlock &MBB = *MI->getParent();
344 DebugLoc DL = MI->getDebugLoc();
345
346 if (!Before)
347 ++MI;
348
349 BuildMI(MBB, MI, DL, TII->get(AMDGPU::S_WAITCNT)).addImm(Vmcnt0Immediate);
350
351 if (!Before)
352 --MI;
353
354 return true;
355}
356
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000357bool SIMemoryLegalizer::removeAtomicPseudoMIs() {
358 if (AtomicPseudoMIs.empty())
359 return false;
360
361 for (auto &MI : AtomicPseudoMIs)
362 MI->eraseFromParent();
363
364 AtomicPseudoMIs.clear();
365 return true;
366}
367
Konstantin Zhuravlyov844845a2017-09-05 16:18:05 +0000368bool SIMemoryLegalizer::expandLoad(const SIMemOpInfo &MOI,
Konstantin Zhuravlyovf5d826a2017-08-18 17:30:02 +0000369 MachineBasicBlock::iterator &MI) {
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000370 assert(MI->mayLoad() && !MI->mayStore());
371
372 bool Changed = false;
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000373
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000374 if (MOI.isAtomic()) {
375 if (MOI.getSSID() == SyncScope::System ||
376 MOI.getSSID() == MMI->getAgentSSID()) {
Konstantin Zhuravlyov8818d132018-02-06 04:06:04 +0000377 if (MOI.getOrdering() == AtomicOrdering::Monotonic ||
378 MOI.getOrdering() == AtomicOrdering::Acquire ||
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000379 MOI.getOrdering() == AtomicOrdering::SequentiallyConsistent)
Konstantin Zhuravlyov5f5b5862017-09-07 17:14:54 +0000380 Changed |= enableGLCBit(MI);
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000381
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000382 if (MOI.getOrdering() == AtomicOrdering::SequentiallyConsistent)
383 Changed |= insertWaitcntVmcnt0(MI);
384
385 if (MOI.getOrdering() == AtomicOrdering::Acquire ||
386 MOI.getOrdering() == AtomicOrdering::SequentiallyConsistent) {
387 Changed |= insertWaitcntVmcnt0(MI, false);
388 Changed |= insertBufferWbinvl1Vol(MI, false);
389 }
390
391 return Changed;
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000392 }
393
394 if (MOI.getSSID() == SyncScope::SingleThread ||
395 MOI.getSSID() == MMI->getWorkgroupSSID() ||
396 MOI.getSSID() == MMI->getWavefrontSSID()) {
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000397 return Changed;
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000398 }
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000399
400 llvm_unreachable("Unsupported synchronization scope");
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000401 }
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000402
Konstantin Zhuravlyov5f5b5862017-09-07 17:14:54 +0000403 // Atomic instructions do not have the nontemporal attribute.
404 if (MOI.isNonTemporal()) {
405 Changed |= enableGLCBit(MI);
406 Changed |= enableSLCBit(MI);
407 return Changed;
408 }
409
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000410 return Changed;
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000411}
412
Konstantin Zhuravlyov844845a2017-09-05 16:18:05 +0000413bool SIMemoryLegalizer::expandStore(const SIMemOpInfo &MOI,
Konstantin Zhuravlyovf5d826a2017-08-18 17:30:02 +0000414 MachineBasicBlock::iterator &MI) {
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000415 assert(!MI->mayLoad() && MI->mayStore());
416
417 bool Changed = false;
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000418
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000419 if (MOI.isAtomic()) {
420 if (MOI.getSSID() == SyncScope::System ||
421 MOI.getSSID() == MMI->getAgentSSID()) {
422 if (MOI.getOrdering() == AtomicOrdering::Release ||
423 MOI.getOrdering() == AtomicOrdering::SequentiallyConsistent)
424 Changed |= insertWaitcntVmcnt0(MI);
425
426 return Changed;
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000427 }
428
429 if (MOI.getSSID() == SyncScope::SingleThread ||
430 MOI.getSSID() == MMI->getWorkgroupSSID() ||
431 MOI.getSSID() == MMI->getWavefrontSSID()) {
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000432 return Changed;
433 }
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000434
435 llvm_unreachable("Unsupported synchronization scope");
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000436 }
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000437
Konstantin Zhuravlyov5f5b5862017-09-07 17:14:54 +0000438 // Atomic instructions do not have the nontemporal attribute.
439 if (MOI.isNonTemporal()) {
440 Changed |= enableGLCBit(MI);
441 Changed |= enableSLCBit(MI);
442 return Changed;
443 }
444
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000445 return Changed;
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000446}
447
Konstantin Zhuravlyov844845a2017-09-05 16:18:05 +0000448bool SIMemoryLegalizer::expandAtomicFence(const SIMemOpInfo &MOI,
Konstantin Zhuravlyov89377c42017-08-19 18:44:27 +0000449 MachineBasicBlock::iterator &MI) {
450 assert(MI->getOpcode() == AMDGPU::ATOMIC_FENCE);
451
452 bool Changed = false;
Konstantin Zhuravlyov89377c42017-08-19 18:44:27 +0000453
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000454 if (MOI.isAtomic()) {
455 if (MOI.getSSID() == SyncScope::System ||
456 MOI.getSSID() == MMI->getAgentSSID()) {
457 if (MOI.getOrdering() == AtomicOrdering::Acquire ||
458 MOI.getOrdering() == AtomicOrdering::Release ||
459 MOI.getOrdering() == AtomicOrdering::AcquireRelease ||
460 MOI.getOrdering() == AtomicOrdering::SequentiallyConsistent)
461 Changed |= insertWaitcntVmcnt0(MI);
Konstantin Zhuravlyov89377c42017-08-19 18:44:27 +0000462
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000463 if (MOI.getOrdering() == AtomicOrdering::Acquire ||
464 MOI.getOrdering() == AtomicOrdering::AcquireRelease ||
465 MOI.getOrdering() == AtomicOrdering::SequentiallyConsistent)
466 Changed |= insertBufferWbinvl1Vol(MI);
467
468 AtomicPseudoMIs.push_back(MI);
469 return Changed;
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000470 }
471
472 if (MOI.getSSID() == SyncScope::SingleThread ||
473 MOI.getSSID() == MMI->getWorkgroupSSID() ||
474 MOI.getSSID() == MMI->getWavefrontSSID()) {
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000475 AtomicPseudoMIs.push_back(MI);
476 return Changed;
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000477 }
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000478
479 SIMemOpInfo::reportUnknownSyncScope(MI);
Konstantin Zhuravlyov89377c42017-08-19 18:44:27 +0000480 }
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000481
482 return Changed;
Konstantin Zhuravlyov89377c42017-08-19 18:44:27 +0000483}
484
Konstantin Zhuravlyov844845a2017-09-05 16:18:05 +0000485bool SIMemoryLegalizer::expandAtomicCmpxchg(const SIMemOpInfo &MOI,
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000486 MachineBasicBlock::iterator &MI) {
487 assert(MI->mayLoad() && MI->mayStore());
488
489 bool Changed = false;
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000490
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000491 if (MOI.isAtomic()) {
492 if (MOI.getSSID() == SyncScope::System ||
493 MOI.getSSID() == MMI->getAgentSSID()) {
494 if (MOI.getOrdering() == AtomicOrdering::Release ||
495 MOI.getOrdering() == AtomicOrdering::AcquireRelease ||
496 MOI.getOrdering() == AtomicOrdering::SequentiallyConsistent ||
497 MOI.getFailureOrdering() == AtomicOrdering::SequentiallyConsistent)
498 Changed |= insertWaitcntVmcnt0(MI);
499
500 if (MOI.getOrdering() == AtomicOrdering::Acquire ||
501 MOI.getOrdering() == AtomicOrdering::AcquireRelease ||
502 MOI.getOrdering() == AtomicOrdering::SequentiallyConsistent ||
503 MOI.getFailureOrdering() == AtomicOrdering::Acquire ||
504 MOI.getFailureOrdering() == AtomicOrdering::SequentiallyConsistent) {
505 Changed |= insertWaitcntVmcnt0(MI, false);
506 Changed |= insertBufferWbinvl1Vol(MI, false);
507 }
508
509 return Changed;
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000510 }
511
512 if (MOI.getSSID() == SyncScope::SingleThread ||
513 MOI.getSSID() == MMI->getWorkgroupSSID() ||
514 MOI.getSSID() == MMI->getWavefrontSSID()) {
Konstantin Zhuravlyov5f5b5862017-09-07 17:14:54 +0000515 Changed |= enableGLCBit(MI);
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000516 return Changed;
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000517 }
Konstantin Zhuravlyovc8c9d4a2017-09-07 16:14:21 +0000518
519 llvm_unreachable("Unsupported synchronization scope");
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000520 }
Konstantin Zhuravlyov80528702017-09-05 19:01:10 +0000521
522 return Changed;
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000523}
524
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000525bool SIMemoryLegalizer::runOnMachineFunction(MachineFunction &MF) {
526 bool Changed = false;
527 const SISubtarget &ST = MF.getSubtarget<SISubtarget>();
528 const IsaInfo::IsaVersion IV = IsaInfo::getIsaVersion(ST.getFeatureBits());
529
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000530 MMI = &MF.getMMI().getObjFileInfo<AMDGPUMachineModuleInfo>();
531 TII = ST.getInstrInfo();
532
533 Vmcnt0Immediate =
534 AMDGPU::encodeWaitcnt(IV, 0, getExpcntBitMask(IV), getLgkmcntBitMask(IV));
535 Wbinvl1Opcode = ST.getGeneration() <= AMDGPUSubtarget::SOUTHERN_ISLANDS ?
536 AMDGPU::BUFFER_WBINVL1 : AMDGPU::BUFFER_WBINVL1_VOL;
537
538 for (auto &MBB : MF) {
539 for (auto MI = MBB.begin(); MI != MBB.end(); ++MI) {
540 if (!(MI->getDesc().TSFlags & SIInstrFlags::maybeAtomic))
541 continue;
542
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +0000543 if (const auto &MOI = SIMemOpInfo::getLoadInfo(MI))
Konstantin Zhuravlyovf5d826a2017-08-18 17:30:02 +0000544 Changed |= expandLoad(MOI.getValue(), MI);
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +0000545 else if (const auto &MOI = SIMemOpInfo::getStoreInfo(MI))
Konstantin Zhuravlyovf5d826a2017-08-18 17:30:02 +0000546 Changed |= expandStore(MOI.getValue(), MI);
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +0000547 else if (const auto &MOI = SIMemOpInfo::getAtomicFenceInfo(MI))
Konstantin Zhuravlyov89377c42017-08-19 18:44:27 +0000548 Changed |= expandAtomicFence(MOI.getValue(), MI);
Konstantin Zhuravlyov1aa667f2017-09-05 16:41:25 +0000549 else if (const auto &MOI = SIMemOpInfo::getAtomicCmpxchgInfo(MI))
Konstantin Zhuravlyovf5d826a2017-08-18 17:30:02 +0000550 Changed |= expandAtomicCmpxchg(MOI.getValue(), MI);
Konstantin Zhuravlyove9a5a772017-07-21 21:19:23 +0000551 }
552 }
553
554 Changed |= removeAtomicPseudoMIs();
555 return Changed;
556}
557
558INITIALIZE_PASS(SIMemoryLegalizer, DEBUG_TYPE, PASS_NAME, false, false)
559
560char SIMemoryLegalizer::ID = 0;
561char &llvm::SIMemoryLegalizerID = SIMemoryLegalizer::ID;
562
563FunctionPass *llvm::createSIMemoryLegalizerPass() {
564 return new SIMemoryLegalizer();
565}