LLVM 24.0.0git
RISCVExpandAtomicPseudoInsts.cpp
Go to the documentation of this file.
1//===-- RISCVExpandAtomicPseudoInsts.cpp - Expand atomic pseudo instrs. ---===//
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 file contains one of the several passes that expand pseudo instructions
10// into target instructions. This pass is run at the last possible moment,
11// avoiding the possibility for other passes to break the requirements for
12// forward progress in the LR/SC block.
13//
14//===----------------------------------------------------------------------===//
15
16#include "RISCV.h"
18#include "RISCVInstrInfo.h"
19#include "RISCVSubtarget.h"
23
24using namespace llvm;
25
26#define RISCV_EXPAND_ATOMIC_PSEUDO_NAME \
27 "RISC-V atomic pseudo instruction expansion pass"
28
29namespace {
30
31class RISCVExpandAtomicPseudoImpl final : public RISCVExpandPseudoImplBase {
33 MachineBasicBlock::iterator &NextMBBI) const override;
34
35 bool expandAtomicBinOp(MachineBasicBlock &MBB,
37 bool IsMasked, int Width,
38 MachineBasicBlock::iterator &NextMBBI) const;
39
40 bool expandAtomicMinMaxOp(MachineBasicBlock &MBB,
42 AtomicRMWInst::BinOp, bool IsMasked, int Width,
43 MachineBasicBlock::iterator &NextMBBI) const;
44
45 bool expandAtomicCmpXchg(MachineBasicBlock &MBB,
46 MachineBasicBlock::iterator MBBI, bool IsMasked,
47 int Width,
48 MachineBasicBlock::iterator &NextMBBI) const;
49
50 unsigned getLRForRMW32(AtomicOrdering Ordering) const;
51 unsigned getSCForRMW32(AtomicOrdering Ordering) const;
52 unsigned getLRForRMW64(AtomicOrdering Ordering) const;
53 unsigned getSCForRMW64(AtomicOrdering Ordering) const;
54 unsigned getLRForRMW(AtomicOrdering Ordering, int Width) const;
55 unsigned getSCForRMW(AtomicOrdering Ordering, int Width) const;
56
57 void doAtomicBinOpExpansion(MachineInstr &MI, MachineBasicBlock *LoopMBB,
58 AtomicRMWInst::BinOp BinOp, int Width) const;
59 void insertMaskedMerge(DebugLoc DL, MachineBasicBlock *MBB, Register DestReg,
60 Register OldValReg, Register NewValReg,
61 Register MaskReg, Register ScratchReg) const;
62 void doMaskedAtomicBinOpExpansion(MachineInstr &MI,
63 MachineBasicBlock *LoopMBB,
65 int Width) const;
66 void insertSext(DebugLoc DL, MachineBasicBlock *MBB, Register ValReg,
67 Register ShamtReg) const;
68 void doAtomicMinMaxOpExpansion(MachineInstr &MI,
69 MachineBasicBlock *LoopHeadMBB,
70 MachineBasicBlock *LoopIfBodyMBB,
71 MachineBasicBlock *LoopTailMBB,
72 AtomicRMWInst::BinOp BinOp, int Width) const;
73 void doMaskedAtomicMinMaxOpExpansion(MachineInstr &MI,
74 MachineBasicBlock *LoopHeadMBB,
75 MachineBasicBlock *LoopIfBodyMBB,
76 MachineBasicBlock *LoopTailMBB,
78 int Width) const;
79 bool tryToFoldBNEOnCmpXchgResult(MachineBasicBlock &MBB,
81 Register DestReg, Register CmpValReg,
82 Register MaskReg,
83 MachineBasicBlock *&LoopHeadBNETarget) const;
84};
85
86class RISCVExpandAtomicPseudoLegacy : public MachineFunctionPass {
87public:
88 static char ID;
89
90 RISCVExpandAtomicPseudoLegacy() : MachineFunctionPass(ID) {}
91
92 bool runOnMachineFunction(MachineFunction &MF) override {
93 return RISCVExpandAtomicPseudoImpl().run(MF);
94 }
95
96 StringRef getPassName() const override {
98 }
99};
100
101} // anonymous namespace
102
103bool RISCVExpandAtomicPseudoImpl::expandMI(
105 MachineBasicBlock::iterator &NextMBBI) const {
106 // RISCVInstrInfo::getInstSizeInBytes expects that the total size of the
107 // expanded instructions for each pseudo is correct in the Size field of the
108 // tablegen definition for the pseudo.
109 switch (MBBI->getOpcode()) {
110 case RISCV::PseudoAtomicSwap32:
111 return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Xchg, false, 32,
112 NextMBBI);
113 case RISCV::PseudoAtomicSwap64:
114 return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Xchg, false, 64,
115 NextMBBI);
116 case RISCV::PseudoAtomicLoadAdd32:
117 return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Add, false, 32,
118 NextMBBI);
119 case RISCV::PseudoAtomicLoadAdd64:
120 return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Add, false, 64,
121 NextMBBI);
122 case RISCV::PseudoAtomicLoadSub32:
123 return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Sub, false, 32,
124 NextMBBI);
125 case RISCV::PseudoAtomicLoadSub64:
126 return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Sub, false, 64,
127 NextMBBI);
128 case RISCV::PseudoAtomicLoadAnd32:
129 return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::And, false, 32,
130 NextMBBI);
131 case RISCV::PseudoAtomicLoadAnd64:
132 return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::And, false, 64,
133 NextMBBI);
134 case RISCV::PseudoAtomicLoadOr32:
135 return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Or, false, 32, NextMBBI);
136 case RISCV::PseudoAtomicLoadOr64:
137 return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Or, false, 64, NextMBBI);
138 case RISCV::PseudoAtomicLoadXor32:
139 return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Xor, false, 32,
140 NextMBBI);
141 case RISCV::PseudoAtomicLoadXor64:
142 return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Xor, false, 64,
143 NextMBBI);
144 case RISCV::PseudoAtomicLoadNand32:
145 return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Nand, false, 32,
146 NextMBBI);
147 case RISCV::PseudoAtomicLoadNand64:
148 return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Nand, false, 64,
149 NextMBBI);
150 case RISCV::PseudoAtomicLoadMin32:
151 return expandAtomicMinMaxOp(MBB, MBBI, AtomicRMWInst::Min, false, 32,
152 NextMBBI);
153 case RISCV::PseudoAtomicLoadMin64:
154 return expandAtomicMinMaxOp(MBB, MBBI, AtomicRMWInst::Min, false, 64,
155 NextMBBI);
156 case RISCV::PseudoAtomicLoadMax32:
157 return expandAtomicMinMaxOp(MBB, MBBI, AtomicRMWInst::Max, false, 32,
158 NextMBBI);
159 case RISCV::PseudoAtomicLoadMax64:
160 return expandAtomicMinMaxOp(MBB, MBBI, AtomicRMWInst::Max, false, 64,
161 NextMBBI);
162 case RISCV::PseudoAtomicLoadUMin32:
163 return expandAtomicMinMaxOp(MBB, MBBI, AtomicRMWInst::UMin, false, 32,
164 NextMBBI);
165 case RISCV::PseudoAtomicLoadUMin64:
166 return expandAtomicMinMaxOp(MBB, MBBI, AtomicRMWInst::UMin, false, 64,
167 NextMBBI);
168 case RISCV::PseudoAtomicLoadUMax32:
169 return expandAtomicMinMaxOp(MBB, MBBI, AtomicRMWInst::UMax, false, 32,
170 NextMBBI);
171 case RISCV::PseudoAtomicLoadUMax64:
172 return expandAtomicMinMaxOp(MBB, MBBI, AtomicRMWInst::UMax, false, 64,
173 NextMBBI);
174 case RISCV::PseudoMaskedAtomicSwap32:
175 return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Xchg, true, 32,
176 NextMBBI);
177 case RISCV::PseudoMaskedAtomicLoadAdd32:
178 return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Add, true, 32, NextMBBI);
179 case RISCV::PseudoMaskedAtomicLoadSub32:
180 return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Sub, true, 32, NextMBBI);
181 case RISCV::PseudoMaskedAtomicLoadNand32:
182 return expandAtomicBinOp(MBB, MBBI, AtomicRMWInst::Nand, true, 32,
183 NextMBBI);
184 case RISCV::PseudoMaskedAtomicLoadMax32:
185 return expandAtomicMinMaxOp(MBB, MBBI, AtomicRMWInst::Max, true, 32,
186 NextMBBI);
187 case RISCV::PseudoMaskedAtomicLoadMin32:
188 return expandAtomicMinMaxOp(MBB, MBBI, AtomicRMWInst::Min, true, 32,
189 NextMBBI);
190 case RISCV::PseudoMaskedAtomicLoadUMax32:
191 return expandAtomicMinMaxOp(MBB, MBBI, AtomicRMWInst::UMax, true, 32,
192 NextMBBI);
193 case RISCV::PseudoMaskedAtomicLoadUMin32:
194 return expandAtomicMinMaxOp(MBB, MBBI, AtomicRMWInst::UMin, true, 32,
195 NextMBBI);
196 case RISCV::PseudoCmpXchg32:
197 return expandAtomicCmpXchg(MBB, MBBI, false, 32, NextMBBI);
198 case RISCV::PseudoCmpXchg64:
199 return expandAtomicCmpXchg(MBB, MBBI, false, 64, NextMBBI);
200 case RISCV::PseudoMaskedCmpXchg32:
201 return expandAtomicCmpXchg(MBB, MBBI, true, 32, NextMBBI);
202 }
203
204 return false;
205}
206
207unsigned
208RISCVExpandAtomicPseudoImpl::getLRForRMW32(AtomicOrdering Ordering) const {
209 switch (Ordering) {
210 default:
211 llvm_unreachable("Unexpected AtomicOrdering");
212 case AtomicOrdering::Monotonic:
213 return RISCV::LR_W;
214 case AtomicOrdering::Acquire:
215 if (STI->hasStdExtZtso())
216 return RISCV::LR_W;
217 return RISCV::LR_W_AQ;
218 case AtomicOrdering::Release:
219 return RISCV::LR_W;
220 case AtomicOrdering::AcquireRelease:
221 if (STI->hasStdExtZtso())
222 return RISCV::LR_W;
223 return RISCV::LR_W_AQ;
224 case AtomicOrdering::SequentiallyConsistent:
225 return RISCV::LR_W_AQRL;
226 }
227}
228
229unsigned
230RISCVExpandAtomicPseudoImpl::getSCForRMW32(AtomicOrdering Ordering) const {
231 switch (Ordering) {
232 default:
233 llvm_unreachable("Unexpected AtomicOrdering");
234 case AtomicOrdering::Monotonic:
235 return RISCV::SC_W;
236 case AtomicOrdering::Acquire:
237 return RISCV::SC_W;
238 case AtomicOrdering::Release:
239 if (STI->hasStdExtZtso())
240 return RISCV::SC_W;
241 return RISCV::SC_W_RL;
242 case AtomicOrdering::AcquireRelease:
243 if (STI->hasStdExtZtso())
244 return RISCV::SC_W;
245 return RISCV::SC_W_RL;
246 case AtomicOrdering::SequentiallyConsistent:
247 return RISCV::SC_W_RL;
248 }
249}
250
251unsigned
252RISCVExpandAtomicPseudoImpl::getLRForRMW64(AtomicOrdering Ordering) const {
253 switch (Ordering) {
254 default:
255 llvm_unreachable("Unexpected AtomicOrdering");
256 case AtomicOrdering::Monotonic:
257 return RISCV::LR_D;
258 case AtomicOrdering::Acquire:
259 if (STI->hasStdExtZtso())
260 return RISCV::LR_D;
261 return RISCV::LR_D_AQ;
262 case AtomicOrdering::Release:
263 return RISCV::LR_D;
264 case AtomicOrdering::AcquireRelease:
265 if (STI->hasStdExtZtso())
266 return RISCV::LR_D;
267 return RISCV::LR_D_AQ;
268 case AtomicOrdering::SequentiallyConsistent:
269 return RISCV::LR_D_AQRL;
270 }
271}
272
273unsigned
274RISCVExpandAtomicPseudoImpl::getSCForRMW64(AtomicOrdering Ordering) const {
275 switch (Ordering) {
276 default:
277 llvm_unreachable("Unexpected AtomicOrdering");
278 case AtomicOrdering::Monotonic:
279 return RISCV::SC_D;
280 case AtomicOrdering::Acquire:
281 return RISCV::SC_D;
282 case AtomicOrdering::Release:
283 if (STI->hasStdExtZtso())
284 return RISCV::SC_D;
285 return RISCV::SC_D_RL;
286 case AtomicOrdering::AcquireRelease:
287 if (STI->hasStdExtZtso())
288 return RISCV::SC_D;
289 return RISCV::SC_D_RL;
290 case AtomicOrdering::SequentiallyConsistent:
291 return RISCV::SC_D_RL;
292 }
293}
294
295unsigned RISCVExpandAtomicPseudoImpl::getLRForRMW(AtomicOrdering Ordering,
296 int Width) const {
297 if (Width == 32)
298 return getLRForRMW32(Ordering);
299 if (Width == 64)
300 return getLRForRMW64(Ordering);
301 llvm_unreachable("Unexpected LR width\n");
302}
303
304unsigned RISCVExpandAtomicPseudoImpl::getSCForRMW(AtomicOrdering Ordering,
305 int Width) const {
306 if (Width == 32)
307 return getSCForRMW32(Ordering);
308 if (Width == 64)
309 return getSCForRMW64(Ordering);
310 llvm_unreachable("Unexpected SC width\n");
311}
312
313void RISCVExpandAtomicPseudoImpl::doAtomicBinOpExpansion(
314 MachineInstr &MI, MachineBasicBlock *LoopMBB, AtomicRMWInst::BinOp BinOp,
315 int Width) const {
316 DebugLoc DL = MI.getDebugLoc();
317 Register DestReg = MI.getOperand(0).getReg();
318 Register ScratchReg = MI.getOperand(1).getReg();
319 Register AddrReg = MI.getOperand(2).getReg();
320 Register IncrReg = MI.getOperand(3).getReg();
322 static_cast<AtomicOrdering>(MI.getOperand(4).getImm());
323
324 // .loop:
325 // lr.[w|d] dest, (addr)
326 // binop scratch, dest, val
327 // sc.[w|d] scratch, scratch, (addr)
328 // bnez scratch, loop
329 BuildMI(LoopMBB, DL, TII->get(getLRForRMW(Ordering, Width)), DestReg)
330 .addReg(AddrReg);
331 switch (BinOp) {
332 default:
333 llvm_unreachable("Unexpected AtomicRMW BinOp");
335 BuildMI(LoopMBB, DL, TII->get(RISCV::ADDI), ScratchReg)
336 .addReg(IncrReg)
337 .addImm(0);
338 break;
340 BuildMI(LoopMBB, DL, TII->get(RISCV::ADD), ScratchReg)
341 .addReg(DestReg)
342 .addReg(IncrReg);
343 break;
345 BuildMI(LoopMBB, DL, TII->get(RISCV::SUB), ScratchReg)
346 .addReg(DestReg)
347 .addReg(IncrReg);
348 break;
350 BuildMI(LoopMBB, DL, TII->get(RISCV::AND), ScratchReg)
351 .addReg(DestReg)
352 .addReg(IncrReg);
353 break;
355 BuildMI(LoopMBB, DL, TII->get(RISCV::OR), ScratchReg)
356 .addReg(DestReg)
357 .addReg(IncrReg);
358 break;
360 BuildMI(LoopMBB, DL, TII->get(RISCV::XOR), ScratchReg)
361 .addReg(DestReg)
362 .addReg(IncrReg);
363 break;
365 BuildMI(LoopMBB, DL, TII->get(RISCV::AND), ScratchReg)
366 .addReg(DestReg)
367 .addReg(IncrReg);
368 BuildMI(LoopMBB, DL, TII->get(RISCV::XORI), ScratchReg)
369 .addReg(ScratchReg)
370 .addImm(-1);
371 break;
373 BuildMI(LoopMBB, DL, TII->get(RISCV::MAX), ScratchReg)
374 .addReg(DestReg)
375 .addReg(IncrReg);
376 break;
378 BuildMI(LoopMBB, DL, TII->get(RISCV::MIN), ScratchReg)
379 .addReg(DestReg)
380 .addReg(IncrReg);
381 break;
383 BuildMI(LoopMBB, DL, TII->get(RISCV::MAXU), ScratchReg)
384 .addReg(DestReg)
385 .addReg(IncrReg);
386 break;
388 BuildMI(LoopMBB, DL, TII->get(RISCV::MINU), ScratchReg)
389 .addReg(DestReg)
390 .addReg(IncrReg);
391 break;
392 }
393 BuildMI(LoopMBB, DL, TII->get(getSCForRMW(Ordering, Width)), ScratchReg)
394 .addReg(ScratchReg)
395 .addReg(AddrReg);
396 BuildMI(LoopMBB, DL, TII->get(RISCV::BNE))
397 .addReg(ScratchReg)
398 .addReg(RISCV::X0)
399 .addMBB(LoopMBB);
400}
401
402void RISCVExpandAtomicPseudoImpl::insertMaskedMerge(
403 DebugLoc DL, MachineBasicBlock *MBB, Register DestReg, Register OldValReg,
404 Register NewValReg, Register MaskReg, Register ScratchReg) const {
405 assert(OldValReg != ScratchReg && "OldValReg and ScratchReg must be unique");
406 assert(OldValReg != MaskReg && "OldValReg and MaskReg must be unique");
407 assert(ScratchReg != MaskReg && "ScratchReg and MaskReg must be unique");
408
409 // We select bits from newval and oldval using:
410 // https://graphics.stanford.edu/~seander/bithacks.html#MaskedMerge
411 // r = oldval ^ ((oldval ^ newval) & masktargetdata);
412 BuildMI(MBB, DL, TII->get(RISCV::XOR), ScratchReg)
413 .addReg(OldValReg)
414 .addReg(NewValReg);
415 BuildMI(MBB, DL, TII->get(RISCV::AND), ScratchReg)
416 .addReg(ScratchReg)
417 .addReg(MaskReg);
418 BuildMI(MBB, DL, TII->get(RISCV::XOR), DestReg)
419 .addReg(OldValReg)
420 .addReg(ScratchReg);
421}
422
423void RISCVExpandAtomicPseudoImpl::doMaskedAtomicBinOpExpansion(
424 MachineInstr &MI, MachineBasicBlock *LoopMBB, AtomicRMWInst::BinOp BinOp,
425 int Width) const {
426 DebugLoc DL = MI.getDebugLoc();
427 assert(Width == 32 && "Should never need to expand masked 64-bit operations");
428 Register DestReg = MI.getOperand(0).getReg();
429 Register ScratchReg = MI.getOperand(1).getReg();
430 Register AddrReg = MI.getOperand(2).getReg();
431 Register IncrReg = MI.getOperand(3).getReg();
432 Register MaskReg = MI.getOperand(4).getReg();
434 static_cast<AtomicOrdering>(MI.getOperand(5).getImm());
435
436 // .loop:
437 // lr.w destreg, (alignedaddr)
438 // binop scratch, destreg, incr
439 // xor scratch, destreg, scratch
440 // and scratch, scratch, masktargetdata
441 // xor scratch, destreg, scratch
442 // sc.w scratch, scratch, (alignedaddr)
443 // bnez scratch, loop
444 BuildMI(LoopMBB, DL, TII->get(getLRForRMW32(Ordering)), DestReg)
445 .addReg(AddrReg);
446 switch (BinOp) {
447 default:
448 llvm_unreachable("Unexpected AtomicRMW BinOp");
450 BuildMI(LoopMBB, DL, TII->get(RISCV::ADDI), ScratchReg)
451 .addReg(IncrReg)
452 .addImm(0);
453 break;
455 BuildMI(LoopMBB, DL, TII->get(RISCV::ADD), ScratchReg)
456 .addReg(DestReg)
457 .addReg(IncrReg);
458 break;
460 BuildMI(LoopMBB, DL, TII->get(RISCV::SUB), ScratchReg)
461 .addReg(DestReg)
462 .addReg(IncrReg);
463 break;
465 BuildMI(LoopMBB, DL, TII->get(RISCV::AND), ScratchReg)
466 .addReg(DestReg)
467 .addReg(IncrReg);
468 BuildMI(LoopMBB, DL, TII->get(RISCV::XORI), ScratchReg)
469 .addReg(ScratchReg)
470 .addImm(-1);
471 break;
472 }
473
474 insertMaskedMerge(DL, LoopMBB, ScratchReg, DestReg, ScratchReg, MaskReg,
475 ScratchReg);
476
477 BuildMI(LoopMBB, DL, TII->get(getSCForRMW32(Ordering)), ScratchReg)
478 .addReg(ScratchReg)
479 .addReg(AddrReg);
480 BuildMI(LoopMBB, DL, TII->get(RISCV::BNE))
481 .addReg(ScratchReg)
482 .addReg(RISCV::X0)
483 .addMBB(LoopMBB);
484}
485
486bool RISCVExpandAtomicPseudoImpl::expandAtomicBinOp(
487 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
488 AtomicRMWInst::BinOp BinOp, bool IsMasked, int Width,
489 MachineBasicBlock::iterator &NextMBBI) const {
490 MachineInstr &MI = *MBBI;
492 auto LoopMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
493 auto DoneMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
494
495 // Insert new MBBs.
496 MF->insert(++MBB.getIterator(), LoopMBB);
497 MF->insert(++LoopMBB->getIterator(), DoneMBB);
498
499 // Set up successors and transfer remaining instructions to DoneMBB.
500 LoopMBB->addSuccessor(LoopMBB);
501 LoopMBB->addSuccessor(DoneMBB);
502 DoneMBB->splice(DoneMBB->end(), &MBB, MI, MBB.end());
503 DoneMBB->transferSuccessors(&MBB);
504 MBB.addSuccessor(LoopMBB);
505
506 if (!IsMasked)
507 doAtomicBinOpExpansion(MI, LoopMBB, BinOp, Width);
508 else
509 doMaskedAtomicBinOpExpansion(MI, LoopMBB, BinOp, Width);
510
511 NextMBBI = MBB.end();
512 MI.eraseFromParent();
513
514 LivePhysRegs LiveRegs;
515 computeAndAddLiveIns(LiveRegs, *LoopMBB);
516 computeAndAddLiveIns(LiveRegs, *DoneMBB);
517
518 return true;
519}
520
521void RISCVExpandAtomicPseudoImpl::insertSext(DebugLoc DL,
522 MachineBasicBlock *MBB,
523 Register ValReg,
524 Register ShamtReg) const {
525 BuildMI(MBB, DL, TII->get(RISCV::SLL), ValReg)
526 .addReg(ValReg)
527 .addReg(ShamtReg);
528 BuildMI(MBB, DL, TII->get(RISCV::SRA), ValReg)
529 .addReg(ValReg)
530 .addReg(ShamtReg);
531}
532
533void RISCVExpandAtomicPseudoImpl::doAtomicMinMaxOpExpansion(
534 MachineInstr &MI, MachineBasicBlock *LoopHeadMBB,
535 MachineBasicBlock *LoopIfBodyMBB, MachineBasicBlock *LoopTailMBB,
536 AtomicRMWInst::BinOp BinOp, int Width) const {
537 DebugLoc DL = MI.getDebugLoc();
538 Register DestReg = MI.getOperand(0).getReg();
539 Register ScratchReg = MI.getOperand(1).getReg();
540 Register AddrReg = MI.getOperand(2).getReg();
541 Register IncrReg = MI.getOperand(3).getReg();
543 static_cast<AtomicOrdering>(MI.getOperand(4).getImm());
544
545 // .loophead:
546 // lr.[w|d] dest, (addr)
547 // mv scratch, dest
548 // ifnochangeneeded scratch, incr, .looptail
549 BuildMI(LoopHeadMBB, DL, TII->get(getLRForRMW(Ordering, Width)), DestReg)
550 .addReg(AddrReg);
551 BuildMI(LoopHeadMBB, DL, TII->get(RISCV::ADDI), ScratchReg)
552 .addReg(DestReg)
553 .addImm(0);
554 switch (BinOp) {
555 default:
556 llvm_unreachable("Unexpected AtomicRMW BinOp");
557 case AtomicRMWInst::Max: {
558 BuildMI(LoopHeadMBB, DL, TII->get(RISCV::BGE))
559 .addReg(ScratchReg)
560 .addReg(IncrReg)
561 .addMBB(LoopTailMBB);
562 break;
563 }
564 case AtomicRMWInst::Min: {
565 BuildMI(LoopHeadMBB, DL, TII->get(RISCV::BGE))
566 .addReg(IncrReg)
567 .addReg(ScratchReg)
568 .addMBB(LoopTailMBB);
569 break;
570 }
572 BuildMI(LoopHeadMBB, DL, TII->get(RISCV::BGEU))
573 .addReg(ScratchReg)
574 .addReg(IncrReg)
575 .addMBB(LoopTailMBB);
576 break;
578 BuildMI(LoopHeadMBB, DL, TII->get(RISCV::BGEU))
579 .addReg(IncrReg)
580 .addReg(ScratchReg)
581 .addMBB(LoopTailMBB);
582 break;
583 }
584
585 // .loopifbody:
586 // mv scratch, incr
587 BuildMI(LoopIfBodyMBB, DL, TII->get(RISCV::ADDI), ScratchReg)
588 .addReg(IncrReg)
589 .addImm(0);
590
591 // .looptail:
592 // sc.[w|d] scratch, scratch, (addr)
593 // bnez scratch, loop
594 BuildMI(LoopTailMBB, DL, TII->get(getSCForRMW(Ordering, Width)), ScratchReg)
595 .addReg(ScratchReg)
596 .addReg(AddrReg);
597 BuildMI(LoopTailMBB, DL, TII->get(RISCV::BNE))
598 .addReg(ScratchReg)
599 .addReg(RISCV::X0)
600 .addMBB(LoopHeadMBB);
601}
602
603void RISCVExpandAtomicPseudoImpl::doMaskedAtomicMinMaxOpExpansion(
604 MachineInstr &MI, MachineBasicBlock *LoopHeadMBB,
605 MachineBasicBlock *LoopIfBodyMBB, MachineBasicBlock *LoopTailMBB,
606 AtomicRMWInst::BinOp BinOp, int Width) const {
607 DebugLoc DL = MI.getDebugLoc();
608 assert(Width == 32 && "Should never need to expand masked 64-bit operations");
609 Register DestReg = MI.getOperand(0).getReg();
610 Register Scratch1Reg = MI.getOperand(1).getReg();
611 Register Scratch2Reg = MI.getOperand(2).getReg();
612 Register AddrReg = MI.getOperand(3).getReg();
613 Register IncrReg = MI.getOperand(4).getReg();
614 Register MaskReg = MI.getOperand(5).getReg();
615 bool IsSigned = BinOp == AtomicRMWInst::Min || BinOp == AtomicRMWInst::Max;
617 static_cast<AtomicOrdering>(MI.getOperand(IsSigned ? 7 : 6).getImm());
618
619 //
620 // .loophead:
621 // lr.w destreg, (alignedaddr)
622 // and scratch2, destreg, mask
623 // mv scratch1, destreg
624 // [sext scratch2 if signed min/max]
625 // ifnochangeneeded scratch2, incr, .looptail
626 BuildMI(LoopHeadMBB, DL, TII->get(getLRForRMW32(Ordering)), DestReg)
627 .addReg(AddrReg);
628 BuildMI(LoopHeadMBB, DL, TII->get(RISCV::AND), Scratch2Reg)
629 .addReg(DestReg)
630 .addReg(MaskReg);
631 BuildMI(LoopHeadMBB, DL, TII->get(RISCV::ADDI), Scratch1Reg)
632 .addReg(DestReg)
633 .addImm(0);
634
635 switch (BinOp) {
636 default:
637 llvm_unreachable("Unexpected AtomicRMW BinOp");
638 case AtomicRMWInst::Max: {
639 insertSext(DL, LoopHeadMBB, Scratch2Reg, MI.getOperand(6).getReg());
640 BuildMI(LoopHeadMBB, DL, TII->get(RISCV::BGE))
641 .addReg(Scratch2Reg)
642 .addReg(IncrReg)
643 .addMBB(LoopTailMBB);
644 break;
645 }
646 case AtomicRMWInst::Min: {
647 insertSext(DL, LoopHeadMBB, Scratch2Reg, MI.getOperand(6).getReg());
648 BuildMI(LoopHeadMBB, DL, TII->get(RISCV::BGE))
649 .addReg(IncrReg)
650 .addReg(Scratch2Reg)
651 .addMBB(LoopTailMBB);
652 break;
653 }
655 BuildMI(LoopHeadMBB, DL, TII->get(RISCV::BGEU))
656 .addReg(Scratch2Reg)
657 .addReg(IncrReg)
658 .addMBB(LoopTailMBB);
659 break;
661 BuildMI(LoopHeadMBB, DL, TII->get(RISCV::BGEU))
662 .addReg(IncrReg)
663 .addReg(Scratch2Reg)
664 .addMBB(LoopTailMBB);
665 break;
666 }
667
668 // .loopifbody:
669 // xor scratch1, destreg, incr
670 // and scratch1, scratch1, mask
671 // xor scratch1, destreg, scratch1
672 insertMaskedMerge(DL, LoopIfBodyMBB, Scratch1Reg, DestReg, IncrReg, MaskReg,
673 Scratch1Reg);
674
675 // .looptail:
676 // sc.w scratch1, scratch1, (addr)
677 // bnez scratch1, loop
678 BuildMI(LoopTailMBB, DL, TII->get(getSCForRMW32(Ordering)), Scratch1Reg)
679 .addReg(Scratch1Reg)
680 .addReg(AddrReg);
681 BuildMI(LoopTailMBB, DL, TII->get(RISCV::BNE))
682 .addReg(Scratch1Reg)
683 .addReg(RISCV::X0)
684 .addMBB(LoopHeadMBB);
685}
686
687bool RISCVExpandAtomicPseudoImpl::expandAtomicMinMaxOp(
688 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
689 AtomicRMWInst::BinOp BinOp, bool IsMasked, int Width,
690 MachineBasicBlock::iterator &NextMBBI) const {
691 // Using MIN(U)/MAX(U) is preferrable if permitted
692 if (STI->hasPermissiveZalrsc() && STI->hasStdExtZbb() && !IsMasked)
693 return expandAtomicBinOp(MBB, MBBI, BinOp, IsMasked, Width, NextMBBI);
694
695 MachineInstr &MI = *MBBI;
697 auto LoopHeadMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
698 auto LoopIfBodyMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
699 auto LoopTailMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
700 auto DoneMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
701
702 // Insert new MBBs.
703 MF->insert(++MBB.getIterator(), LoopHeadMBB);
704 MF->insert(++LoopHeadMBB->getIterator(), LoopIfBodyMBB);
705 MF->insert(++LoopIfBodyMBB->getIterator(), LoopTailMBB);
706 MF->insert(++LoopTailMBB->getIterator(), DoneMBB);
707
708 // Set up successors and transfer remaining instructions to DoneMBB.
709 LoopHeadMBB->addSuccessor(LoopIfBodyMBB);
710 LoopHeadMBB->addSuccessor(LoopTailMBB);
711 LoopIfBodyMBB->addSuccessor(LoopTailMBB);
712 LoopTailMBB->addSuccessor(LoopHeadMBB);
713 LoopTailMBB->addSuccessor(DoneMBB);
714 DoneMBB->splice(DoneMBB->end(), &MBB, MI, MBB.end());
715 DoneMBB->transferSuccessors(&MBB);
716 MBB.addSuccessor(LoopHeadMBB);
717
718 if (!IsMasked)
719 doAtomicMinMaxOpExpansion(MI, LoopHeadMBB, LoopIfBodyMBB, LoopTailMBB,
720 BinOp, Width);
721 else
722 doMaskedAtomicMinMaxOpExpansion(MI, LoopHeadMBB, LoopIfBodyMBB, LoopTailMBB,
723 BinOp, Width);
724
725 NextMBBI = MBB.end();
726 MI.eraseFromParent();
727
728 LivePhysRegs LiveRegs;
729 computeAndAddLiveIns(LiveRegs, *LoopHeadMBB);
730 computeAndAddLiveIns(LiveRegs, *LoopIfBodyMBB);
731 computeAndAddLiveIns(LiveRegs, *LoopTailMBB);
732 computeAndAddLiveIns(LiveRegs, *DoneMBB);
733
734 return true;
735}
736
737// If a BNE on the cmpxchg comparison result immediately follows the cmpxchg
738// operation, it can be folded into the cmpxchg expansion by
739// modifying the branch within 'LoopHead' (which performs the same
740// comparison). This is a valid transformation because after altering the
741// LoopHead's BNE destination, the BNE following the cmpxchg becomes
742// redundant and and be deleted. In the case of a masked cmpxchg, an
743// appropriate AND and BNE must be matched.
744//
745// On success, returns true and deletes the matching BNE or AND+BNE, sets the
746// LoopHeadBNETarget argument to the target that should be used within the
747// loop head, and removes that block as a successor to MBB.
748bool RISCVExpandAtomicPseudoImpl::tryToFoldBNEOnCmpXchgResult(
749 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, Register DestReg,
750 Register CmpValReg, Register MaskReg,
751 MachineBasicBlock *&LoopHeadBNETarget) const {
753 auto E = MBB.end();
754 if (MBBI == E)
755 return false;
757
758 // If we have a masked cmpxchg, match AND dst, DestReg, MaskReg.
759 if (MaskReg.isValid()) {
760 if (MBBI == E || MBBI->getOpcode() != RISCV::AND)
761 return false;
762 Register ANDOp1 = MBBI->getOperand(1).getReg();
763 Register ANDOp2 = MBBI->getOperand(2).getReg();
764 if (!(ANDOp1 == DestReg && ANDOp2 == MaskReg) &&
765 !(ANDOp1 == MaskReg && ANDOp2 == DestReg))
766 return false;
767 // We now expect the BNE to use the result of the AND as an operand.
768 DestReg = MBBI->getOperand(0).getReg();
769 ToErase.push_back(&*MBBI);
771 }
772
773 // Match BNE DestReg, MaskReg.
774 if (MBBI == E || MBBI->getOpcode() != RISCV::BNE)
775 return false;
776 Register BNEOp0 = MBBI->getOperand(0).getReg();
777 Register BNEOp1 = MBBI->getOperand(1).getReg();
778 if (!(BNEOp0 == DestReg && BNEOp1 == CmpValReg) &&
779 !(BNEOp0 == CmpValReg && BNEOp1 == DestReg))
780 return false;
781
782 // Make sure the branch is the only user of the AND.
783 if (MaskReg.isValid()) {
784 if (BNEOp0 == DestReg && !MBBI->getOperand(0).isKill())
785 return false;
786 if (BNEOp1 == DestReg && !MBBI->getOperand(1).isKill())
787 return false;
788 }
789
790 ToErase.push_back(&*MBBI);
791 LoopHeadBNETarget = MBBI->getOperand(2).getMBB();
793 if (MBBI != E)
794 return false;
795
796 MBB.removeSuccessor(LoopHeadBNETarget);
797 for (auto *MI : ToErase)
798 MI->eraseFromParent();
799 return true;
800}
801
802bool RISCVExpandAtomicPseudoImpl::expandAtomicCmpXchg(
803 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, bool IsMasked,
804 int Width, MachineBasicBlock::iterator &NextMBBI) const {
805 MachineInstr &MI = *MBBI;
806 DebugLoc DL = MI.getDebugLoc();
808 auto LoopHeadMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
809 auto LoopTailMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
810 auto DoneMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
811
812 Register DestReg = MI.getOperand(0).getReg();
813 Register ScratchReg = MI.getOperand(1).getReg();
814 Register AddrReg = MI.getOperand(2).getReg();
815 Register CmpValReg = MI.getOperand(3).getReg();
816 Register NewValReg = MI.getOperand(4).getReg();
817 Register MaskReg = IsMasked ? MI.getOperand(5).getReg() : Register();
818
819 MachineBasicBlock *LoopHeadBNETarget = DoneMBB;
820 tryToFoldBNEOnCmpXchgResult(MBB, std::next(MBBI), DestReg, CmpValReg, MaskReg,
821 LoopHeadBNETarget);
822
823 // Insert new MBBs.
824 MF->insert(++MBB.getIterator(), LoopHeadMBB);
825 MF->insert(++LoopHeadMBB->getIterator(), LoopTailMBB);
826 MF->insert(++LoopTailMBB->getIterator(), DoneMBB);
827
828 // Set up successors and transfer remaining instructions to DoneMBB.
829 LoopHeadMBB->addSuccessor(LoopTailMBB);
830 LoopHeadMBB->addSuccessor(LoopHeadBNETarget);
831 LoopTailMBB->addSuccessor(DoneMBB);
832 LoopTailMBB->addSuccessor(LoopHeadMBB);
833 DoneMBB->splice(DoneMBB->end(), &MBB, MI, MBB.end());
834 DoneMBB->transferSuccessors(&MBB);
835 MBB.addSuccessor(LoopHeadMBB);
836
838 static_cast<AtomicOrdering>(MI.getOperand(IsMasked ? 6 : 5).getImm());
839
840 if (!IsMasked) {
841 // .loophead:
842 // lr.[w|d] dest, (addr)
843 // bne dest, cmpval, done
844 BuildMI(LoopHeadMBB, DL, TII->get(getLRForRMW(Ordering, Width)), DestReg)
845 .addReg(AddrReg);
846 BuildMI(LoopHeadMBB, DL, TII->get(RISCV::BNE))
847 .addReg(DestReg)
848 .addReg(CmpValReg)
849 .addMBB(LoopHeadBNETarget);
850 // .looptail:
851 // sc.[w|d] scratch, newval, (addr)
852 // bnez scratch, loophead
853 BuildMI(LoopTailMBB, DL, TII->get(getSCForRMW(Ordering, Width)), ScratchReg)
854 .addReg(NewValReg)
855 .addReg(AddrReg);
856 BuildMI(LoopTailMBB, DL, TII->get(RISCV::BNE))
857 .addReg(ScratchReg)
858 .addReg(RISCV::X0)
859 .addMBB(LoopHeadMBB);
860 } else {
861 // .loophead:
862 // lr.w dest, (addr)
863 // and scratch, dest, mask
864 // bne scratch, cmpval, done
865 Register MaskReg = MI.getOperand(5).getReg();
866 BuildMI(LoopHeadMBB, DL, TII->get(getLRForRMW(Ordering, Width)), DestReg)
867 .addReg(AddrReg);
868 BuildMI(LoopHeadMBB, DL, TII->get(RISCV::AND), ScratchReg)
869 .addReg(DestReg)
870 .addReg(MaskReg);
871 BuildMI(LoopHeadMBB, DL, TII->get(RISCV::BNE))
872 .addReg(ScratchReg)
873 .addReg(CmpValReg)
874 .addMBB(LoopHeadBNETarget);
875
876 // .looptail:
877 // xor scratch, dest, newval
878 // and scratch, scratch, mask
879 // xor scratch, dest, scratch
880 // sc.w scratch, scratch, (adrr)
881 // bnez scratch, loophead
882 insertMaskedMerge(DL, LoopTailMBB, ScratchReg, DestReg, NewValReg, MaskReg,
883 ScratchReg);
884 BuildMI(LoopTailMBB, DL, TII->get(getSCForRMW(Ordering, Width)), ScratchReg)
885 .addReg(ScratchReg)
886 .addReg(AddrReg);
887 BuildMI(LoopTailMBB, DL, TII->get(RISCV::BNE))
888 .addReg(ScratchReg)
889 .addReg(RISCV::X0)
890 .addMBB(LoopHeadMBB);
891 }
892
893 NextMBBI = MBB.end();
894 MI.eraseFromParent();
895
896 LivePhysRegs LiveRegs;
897 computeAndAddLiveIns(LiveRegs, *LoopHeadMBB);
898 computeAndAddLiveIns(LiveRegs, *LoopTailMBB);
899 computeAndAddLiveIns(LiveRegs, *DoneMBB);
900
901 return true;
902}
903
904char RISCVExpandAtomicPseudoLegacy::ID = 0;
905
906INITIALIZE_PASS(RISCVExpandAtomicPseudoLegacy, "riscv-expand-atomic-pseudo",
908
910 return new RISCVExpandAtomicPseudoLegacy();
911}
912
913PreservedAnalyses
916 bool Changed = RISCVExpandAtomicPseudoImpl().run(MF);
917 if (!Changed)
918 return PreservedAnalyses::all();
920}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
MachineBasicBlock MachineBasicBlock::iterator MBBI
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
This file implements the LivePhysRegs utility for tracking liveness of physical registers.
Promote Memory to Register
Definition Mem2Reg.cpp:110
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
#define RISCV_EXPAND_ATOMIC_PSEUDO_NAME
BinOp
This enumeration lists the possible modifications atomicrmw can make.
@ Add
*p = old + v
@ Min
*p = old <signed v ? old : v
@ Sub
*p = old - v
@ And
*p = old & v
@ Xor
*p = old ^ v
@ Max
*p = old >signed v ? old : v
@ UMin
*p = old <unsigned v ? old : v
@ UMax
*p = old >unsigned v ? old : v
@ Nand
*p = ~(old & v)
A debug info location.
Definition DebugLoc.h:126
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
const BasicBlock * getBasicBlock() const
Return the LLVM basic block that this instance corresponded to originally.
LLVM_ABI void addSuccessor(MachineBasicBlock *Succ, BranchProbability Prob=BranchProbability::getUnknown())
Add Succ as a successor of this MachineBasicBlock.
LLVM_ABI void removeSuccessor(MachineBasicBlock *Succ, bool NormalizeSuccProbs=false)
Remove successor from the successors list of this MachineBasicBlock.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineInstrBundleIterator< MachineInstr > iterator
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
MachineBasicBlock * CreateMachineBasicBlock(const BasicBlock *BB=nullptr, std::optional< UniqueBBID > BBID=std::nullopt)
CreateMachineInstr - Allocate a new MachineInstr.
void insert(iterator MBBI, MachineBasicBlock *MBB)
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 & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
Representation of each machine instruction.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
Wrapper class representing virtual and physical registers.
Definition Register.h:20
constexpr bool isValid() const
Definition Register.h:112
void push_back(const T &Elt)
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
self_iterator getIterator()
Definition ilist_node.h:123
Changed
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
This is an optimization pass for GlobalISel generic memory operations.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
FunctionPass * createRISCVExpandAtomicPseudoLegacyPass()
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
IterT skipDebugInstructionsForward(IterT It, IterT End, bool SkipPseudoOp=true)
Increment It until it points to a non-debug instruction or to End and return the resulting iterator.
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
AtomicOrdering
Atomic ordering for LLVM's memory model.
LLVM_ABI void computeAndAddLiveIns(LivePhysRegs &LiveRegs, MachineBasicBlock &MBB)
Convenience function combining computeLiveIns() and addLiveIns().