aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/llvm/lib/Target/Mips/MipsExpandPseudo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Target/Mips/MipsExpandPseudo.cpp')
-rw-r--r--contrib/llvm-project/llvm/lib/Target/Mips/MipsExpandPseudo.cpp913
1 files changed, 913 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/lib/Target/Mips/MipsExpandPseudo.cpp b/contrib/llvm-project/llvm/lib/Target/Mips/MipsExpandPseudo.cpp
new file mode 100644
index 000000000000..b1abf4a33717
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/Target/Mips/MipsExpandPseudo.cpp
@@ -0,0 +1,913 @@
+//===-- MipsExpandPseudoInsts.cpp - Expand pseudo instructions ------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains a pass that expands pseudo instructions into target
+// instructions to allow proper scheduling, if-conversion, and other late
+// optimizations. This pass should be run after register allocation but before
+// the post-regalloc scheduling pass.
+//
+// This is currently only used for expanding atomic pseudos after register
+// allocation. We do this to avoid the fast register allocator introducing
+// spills between ll and sc. These stores cause some MIPS implementations to
+// abort the atomic RMW sequence.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Mips.h"
+#include "MipsInstrInfo.h"
+#include "MipsSubtarget.h"
+#include "llvm/CodeGen/LivePhysRegs.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "mips-pseudo"
+
+namespace {
+ class MipsExpandPseudo : public MachineFunctionPass {
+ public:
+ static char ID;
+ MipsExpandPseudo() : MachineFunctionPass(ID) {}
+
+ const MipsInstrInfo *TII;
+ const MipsSubtarget *STI;
+
+ bool runOnMachineFunction(MachineFunction &Fn) override;
+
+ MachineFunctionProperties getRequiredProperties() const override {
+ return MachineFunctionProperties().set(
+ MachineFunctionProperties::Property::NoVRegs);
+ }
+
+ StringRef getPassName() const override {
+ return "Mips pseudo instruction expansion pass";
+ }
+
+ private:
+ bool expandAtomicCmpSwap(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MBBI,
+ MachineBasicBlock::iterator &NextMBBI);
+ bool expandAtomicCmpSwapSubword(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MBBI,
+ MachineBasicBlock::iterator &NextMBBI);
+
+ bool expandAtomicBinOp(MachineBasicBlock &BB,
+ MachineBasicBlock::iterator I,
+ MachineBasicBlock::iterator &NMBBI, unsigned Size);
+ bool expandAtomicBinOpSubword(MachineBasicBlock &BB,
+ MachineBasicBlock::iterator I,
+ MachineBasicBlock::iterator &NMBBI);
+
+ bool expandMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
+ MachineBasicBlock::iterator &NMBB);
+ bool expandMBB(MachineBasicBlock &MBB);
+ };
+ char MipsExpandPseudo::ID = 0;
+}
+
+bool MipsExpandPseudo::expandAtomicCmpSwapSubword(
+ MachineBasicBlock &BB, MachineBasicBlock::iterator I,
+ MachineBasicBlock::iterator &NMBBI) {
+
+ MachineFunction *MF = BB.getParent();
+
+ const bool ArePtrs64bit = STI->getABI().ArePtrs64bit();
+ DebugLoc DL = I->getDebugLoc();
+ unsigned LL, SC;
+
+ unsigned ZERO = Mips::ZERO;
+ unsigned BNE = Mips::BNE;
+ unsigned BEQ = Mips::BEQ;
+ unsigned SEOp =
+ I->getOpcode() == Mips::ATOMIC_CMP_SWAP_I8_POSTRA ? Mips::SEB : Mips::SEH;
+
+ if (STI->inMicroMipsMode()) {
+ LL = STI->hasMips32r6() ? Mips::LL_MMR6 : Mips::LL_MM;
+ SC = STI->hasMips32r6() ? Mips::SC_MMR6 : Mips::SC_MM;
+ BNE = STI->hasMips32r6() ? Mips::BNEC_MMR6 : Mips::BNE_MM;
+ BEQ = STI->hasMips32r6() ? Mips::BEQC_MMR6 : Mips::BEQ_MM;
+ } else {
+ LL = STI->hasMips32r6() ? (ArePtrs64bit ? Mips::LL64_R6 : Mips::LL_R6)
+ : (ArePtrs64bit ? Mips::LL64 : Mips::LL);
+ SC = STI->hasMips32r6() ? (ArePtrs64bit ? Mips::SC64_R6 : Mips::SC_R6)
+ : (ArePtrs64bit ? Mips::SC64 : Mips::SC);
+ }
+
+ Register Dest = I->getOperand(0).getReg();
+ Register Ptr = I->getOperand(1).getReg();
+ Register Mask = I->getOperand(2).getReg();
+ Register ShiftCmpVal = I->getOperand(3).getReg();
+ Register Mask2 = I->getOperand(4).getReg();
+ Register ShiftNewVal = I->getOperand(5).getReg();
+ Register ShiftAmnt = I->getOperand(6).getReg();
+ Register Scratch = I->getOperand(7).getReg();
+ Register Scratch2 = I->getOperand(8).getReg();
+
+ // insert new blocks after the current block
+ const BasicBlock *LLVM_BB = BB.getBasicBlock();
+ MachineBasicBlock *loop1MBB = MF->CreateMachineBasicBlock(LLVM_BB);
+ MachineBasicBlock *loop2MBB = MF->CreateMachineBasicBlock(LLVM_BB);
+ MachineBasicBlock *sinkMBB = MF->CreateMachineBasicBlock(LLVM_BB);
+ MachineBasicBlock *exitMBB = MF->CreateMachineBasicBlock(LLVM_BB);
+ MachineFunction::iterator It = ++BB.getIterator();
+ MF->insert(It, loop1MBB);
+ MF->insert(It, loop2MBB);
+ MF->insert(It, sinkMBB);
+ MF->insert(It, exitMBB);
+
+ // Transfer the remainder of BB and its successor edges to exitMBB.
+ exitMBB->splice(exitMBB->begin(), &BB,
+ std::next(MachineBasicBlock::iterator(I)), BB.end());
+ exitMBB->transferSuccessorsAndUpdatePHIs(&BB);
+
+ // thisMBB:
+ // ...
+ // fallthrough --> loop1MBB
+ BB.addSuccessor(loop1MBB, BranchProbability::getOne());
+ loop1MBB->addSuccessor(sinkMBB);
+ loop1MBB->addSuccessor(loop2MBB);
+ loop1MBB->normalizeSuccProbs();
+ loop2MBB->addSuccessor(loop1MBB);
+ loop2MBB->addSuccessor(sinkMBB);
+ loop2MBB->normalizeSuccProbs();
+ sinkMBB->addSuccessor(exitMBB, BranchProbability::getOne());
+
+ // loop1MBB:
+ // ll dest, 0(ptr)
+ // and Mask', dest, Mask
+ // bne Mask', ShiftCmpVal, exitMBB
+ BuildMI(loop1MBB, DL, TII->get(LL), Scratch).addReg(Ptr).addImm(0);
+ BuildMI(loop1MBB, DL, TII->get(Mips::AND), Scratch2)
+ .addReg(Scratch)
+ .addReg(Mask);
+ BuildMI(loop1MBB, DL, TII->get(BNE))
+ .addReg(Scratch2).addReg(ShiftCmpVal).addMBB(sinkMBB);
+
+ // loop2MBB:
+ // and dest, dest, mask2
+ // or dest, dest, ShiftNewVal
+ // sc dest, dest, 0(ptr)
+ // beq dest, $0, loop1MBB
+ BuildMI(loop2MBB, DL, TII->get(Mips::AND), Scratch)
+ .addReg(Scratch, RegState::Kill)
+ .addReg(Mask2);
+ BuildMI(loop2MBB, DL, TII->get(Mips::OR), Scratch)
+ .addReg(Scratch, RegState::Kill)
+ .addReg(ShiftNewVal);
+ BuildMI(loop2MBB, DL, TII->get(SC), Scratch)
+ .addReg(Scratch, RegState::Kill)
+ .addReg(Ptr)
+ .addImm(0);
+ BuildMI(loop2MBB, DL, TII->get(BEQ))
+ .addReg(Scratch, RegState::Kill)
+ .addReg(ZERO)
+ .addMBB(loop1MBB);
+
+ // sinkMBB:
+ // srl srlres, Mask', shiftamt
+ // sign_extend dest,srlres
+ BuildMI(sinkMBB, DL, TII->get(Mips::SRLV), Dest)
+ .addReg(Scratch2)
+ .addReg(ShiftAmnt);
+ if (STI->hasMips32r2()) {
+ BuildMI(sinkMBB, DL, TII->get(SEOp), Dest).addReg(Dest);
+ } else {
+ const unsigned ShiftImm =
+ I->getOpcode() == Mips::ATOMIC_CMP_SWAP_I16_POSTRA ? 16 : 24;
+ BuildMI(sinkMBB, DL, TII->get(Mips::SLL), Dest)
+ .addReg(Dest, RegState::Kill)
+ .addImm(ShiftImm);
+ BuildMI(sinkMBB, DL, TII->get(Mips::SRA), Dest)
+ .addReg(Dest, RegState::Kill)
+ .addImm(ShiftImm);
+ }
+
+ LivePhysRegs LiveRegs;
+ computeAndAddLiveIns(LiveRegs, *loop1MBB);
+ computeAndAddLiveIns(LiveRegs, *loop2MBB);
+ computeAndAddLiveIns(LiveRegs, *sinkMBB);
+ computeAndAddLiveIns(LiveRegs, *exitMBB);
+
+ NMBBI = BB.end();
+ I->eraseFromParent();
+ return true;
+}
+
+bool MipsExpandPseudo::expandAtomicCmpSwap(MachineBasicBlock &BB,
+ MachineBasicBlock::iterator I,
+ MachineBasicBlock::iterator &NMBBI) {
+
+ const unsigned Size =
+ I->getOpcode() == Mips::ATOMIC_CMP_SWAP_I32_POSTRA ? 4 : 8;
+ MachineFunction *MF = BB.getParent();
+
+ const bool ArePtrs64bit = STI->getABI().ArePtrs64bit();
+ DebugLoc DL = I->getDebugLoc();
+
+ unsigned LL, SC, ZERO, BNE, BEQ, MOVE;
+
+ if (Size == 4) {
+ if (STI->inMicroMipsMode()) {
+ LL = STI->hasMips32r6() ? Mips::LL_MMR6 : Mips::LL_MM;
+ SC = STI->hasMips32r6() ? Mips::SC_MMR6 : Mips::SC_MM;
+ BNE = STI->hasMips32r6() ? Mips::BNEC_MMR6 : Mips::BNE_MM;
+ BEQ = STI->hasMips32r6() ? Mips::BEQC_MMR6 : Mips::BEQ_MM;
+ } else {
+ LL = STI->hasMips32r6()
+ ? (ArePtrs64bit ? Mips::LL64_R6 : Mips::LL_R6)
+ : (ArePtrs64bit ? Mips::LL64 : Mips::LL);
+ SC = STI->hasMips32r6()
+ ? (ArePtrs64bit ? Mips::SC64_R6 : Mips::SC_R6)
+ : (ArePtrs64bit ? Mips::SC64 : Mips::SC);
+ BNE = Mips::BNE;
+ BEQ = Mips::BEQ;
+ }
+
+ ZERO = Mips::ZERO;
+ MOVE = Mips::OR;
+ } else {
+ LL = STI->hasMips64r6() ? Mips::LLD_R6 : Mips::LLD;
+ SC = STI->hasMips64r6() ? Mips::SCD_R6 : Mips::SCD;
+ ZERO = Mips::ZERO_64;
+ BNE = Mips::BNE64;
+ BEQ = Mips::BEQ64;
+ MOVE = Mips::OR64;
+ }
+
+ Register Dest = I->getOperand(0).getReg();
+ Register Ptr = I->getOperand(1).getReg();
+ Register OldVal = I->getOperand(2).getReg();
+ Register NewVal = I->getOperand(3).getReg();
+ Register Scratch = I->getOperand(4).getReg();
+
+ // insert new blocks after the current block
+ const BasicBlock *LLVM_BB = BB.getBasicBlock();
+ MachineBasicBlock *loop1MBB = MF->CreateMachineBasicBlock(LLVM_BB);
+ MachineBasicBlock *loop2MBB = MF->CreateMachineBasicBlock(LLVM_BB);
+ MachineBasicBlock *exitMBB = MF->CreateMachineBasicBlock(LLVM_BB);
+ MachineFunction::iterator It = ++BB.getIterator();
+ MF->insert(It, loop1MBB);
+ MF->insert(It, loop2MBB);
+ MF->insert(It, exitMBB);
+
+ // Transfer the remainder of BB and its successor edges to exitMBB.
+ exitMBB->splice(exitMBB->begin(), &BB,
+ std::next(MachineBasicBlock::iterator(I)), BB.end());
+ exitMBB->transferSuccessorsAndUpdatePHIs(&BB);
+
+ // thisMBB:
+ // ...
+ // fallthrough --> loop1MBB
+ BB.addSuccessor(loop1MBB, BranchProbability::getOne());
+ loop1MBB->addSuccessor(exitMBB);
+ loop1MBB->addSuccessor(loop2MBB);
+ loop1MBB->normalizeSuccProbs();
+ loop2MBB->addSuccessor(loop1MBB);
+ loop2MBB->addSuccessor(exitMBB);
+ loop2MBB->normalizeSuccProbs();
+
+ // loop1MBB:
+ // ll dest, 0(ptr)
+ // bne dest, oldval, exitMBB
+ BuildMI(loop1MBB, DL, TII->get(LL), Dest).addReg(Ptr).addImm(0);
+ BuildMI(loop1MBB, DL, TII->get(BNE))
+ .addReg(Dest, RegState::Kill).addReg(OldVal).addMBB(exitMBB);
+
+ // loop2MBB:
+ // move scratch, NewVal
+ // sc Scratch, Scratch, 0(ptr)
+ // beq Scratch, $0, loop1MBB
+ BuildMI(loop2MBB, DL, TII->get(MOVE), Scratch).addReg(NewVal).addReg(ZERO);
+ BuildMI(loop2MBB, DL, TII->get(SC), Scratch)
+ .addReg(Scratch).addReg(Ptr).addImm(0);
+ BuildMI(loop2MBB, DL, TII->get(BEQ))
+ .addReg(Scratch, RegState::Kill).addReg(ZERO).addMBB(loop1MBB);
+
+ LivePhysRegs LiveRegs;
+ computeAndAddLiveIns(LiveRegs, *loop1MBB);
+ computeAndAddLiveIns(LiveRegs, *loop2MBB);
+ computeAndAddLiveIns(LiveRegs, *exitMBB);
+
+ NMBBI = BB.end();
+ I->eraseFromParent();
+ return true;
+}
+
+bool MipsExpandPseudo::expandAtomicBinOpSubword(
+ MachineBasicBlock &BB, MachineBasicBlock::iterator I,
+ MachineBasicBlock::iterator &NMBBI) {
+
+ MachineFunction *MF = BB.getParent();
+
+ const bool ArePtrs64bit = STI->getABI().ArePtrs64bit();
+ DebugLoc DL = I->getDebugLoc();
+
+ unsigned LL, SC, SLT, SLTu, OR, MOVN, MOVZ, SELNEZ, SELEQZ;
+ unsigned BEQ = Mips::BEQ;
+ unsigned SEOp = Mips::SEH;
+
+ if (STI->inMicroMipsMode()) {
+ LL = STI->hasMips32r6() ? Mips::LL_MMR6 : Mips::LL_MM;
+ SC = STI->hasMips32r6() ? Mips::SC_MMR6 : Mips::SC_MM;
+ BEQ = STI->hasMips32r6() ? Mips::BEQC_MMR6 : Mips::BEQ_MM;
+ SLT = Mips::SLT_MM;
+ SLTu = Mips::SLTu_MM;
+ OR = STI->hasMips32r6() ? Mips::OR_MMR6 : Mips::OR_MM;
+ MOVN = Mips::MOVN_I_MM;
+ MOVZ = Mips::MOVZ_I_MM;
+ SELNEZ = STI->hasMips32r6() ? Mips::SELNEZ_MMR6 : Mips::SELNEZ;
+ SELEQZ = STI->hasMips32r6() ? Mips::SELEQZ_MMR6 : Mips::SELEQZ;
+ } else {
+ LL = STI->hasMips32r6() ? (ArePtrs64bit ? Mips::LL64_R6 : Mips::LL_R6)
+ : (ArePtrs64bit ? Mips::LL64 : Mips::LL);
+ SC = STI->hasMips32r6() ? (ArePtrs64bit ? Mips::SC64_R6 : Mips::SC_R6)
+ : (ArePtrs64bit ? Mips::SC64 : Mips::SC);
+ SLT = Mips::SLT;
+ SLTu = Mips::SLTu;
+ OR = Mips::OR;
+ MOVN = Mips::MOVN_I_I;
+ MOVZ = Mips::MOVZ_I_I;
+ SELNEZ = Mips::SELNEZ;
+ SELEQZ = Mips::SELEQZ;
+ }
+
+ bool IsSwap = false;
+ bool IsNand = false;
+ bool IsMin = false;
+ bool IsMax = false;
+ bool IsUnsigned = false;
+
+ unsigned Opcode = 0;
+ switch (I->getOpcode()) {
+ case Mips::ATOMIC_LOAD_NAND_I8_POSTRA:
+ SEOp = Mips::SEB;
+ LLVM_FALLTHROUGH;
+ case Mips::ATOMIC_LOAD_NAND_I16_POSTRA:
+ IsNand = true;
+ break;
+ case Mips::ATOMIC_SWAP_I8_POSTRA:
+ SEOp = Mips::SEB;
+ LLVM_FALLTHROUGH;
+ case Mips::ATOMIC_SWAP_I16_POSTRA:
+ IsSwap = true;
+ break;
+ case Mips::ATOMIC_LOAD_ADD_I8_POSTRA:
+ SEOp = Mips::SEB;
+ LLVM_FALLTHROUGH;
+ case Mips::ATOMIC_LOAD_ADD_I16_POSTRA:
+ Opcode = Mips::ADDu;
+ break;
+ case Mips::ATOMIC_LOAD_SUB_I8_POSTRA:
+ SEOp = Mips::SEB;
+ LLVM_FALLTHROUGH;
+ case Mips::ATOMIC_LOAD_SUB_I16_POSTRA:
+ Opcode = Mips::SUBu;
+ break;
+ case Mips::ATOMIC_LOAD_AND_I8_POSTRA:
+ SEOp = Mips::SEB;
+ LLVM_FALLTHROUGH;
+ case Mips::ATOMIC_LOAD_AND_I16_POSTRA:
+ Opcode = Mips::AND;
+ break;
+ case Mips::ATOMIC_LOAD_OR_I8_POSTRA:
+ SEOp = Mips::SEB;
+ LLVM_FALLTHROUGH;
+ case Mips::ATOMIC_LOAD_OR_I16_POSTRA:
+ Opcode = Mips::OR;
+ break;
+ case Mips::ATOMIC_LOAD_XOR_I8_POSTRA:
+ SEOp = Mips::SEB;
+ LLVM_FALLTHROUGH;
+ case Mips::ATOMIC_LOAD_XOR_I16_POSTRA:
+ Opcode = Mips::XOR;
+ break;
+ case Mips::ATOMIC_LOAD_UMIN_I8_POSTRA:
+ case Mips::ATOMIC_LOAD_UMIN_I16_POSTRA:
+ IsUnsigned = true;
+ LLVM_FALLTHROUGH;
+ case Mips::ATOMIC_LOAD_MIN_I8_POSTRA:
+ case Mips::ATOMIC_LOAD_MIN_I16_POSTRA:
+ IsMin = true;
+ break;
+ case Mips::ATOMIC_LOAD_UMAX_I8_POSTRA:
+ case Mips::ATOMIC_LOAD_UMAX_I16_POSTRA:
+ IsUnsigned = true;
+ LLVM_FALLTHROUGH;
+ case Mips::ATOMIC_LOAD_MAX_I8_POSTRA:
+ case Mips::ATOMIC_LOAD_MAX_I16_POSTRA:
+ IsMax = true;
+ break;
+ default:
+ llvm_unreachable("Unknown subword atomic pseudo for expansion!");
+ }
+
+ Register Dest = I->getOperand(0).getReg();
+ Register Ptr = I->getOperand(1).getReg();
+ Register Incr = I->getOperand(2).getReg();
+ Register Mask = I->getOperand(3).getReg();
+ Register Mask2 = I->getOperand(4).getReg();
+ Register ShiftAmnt = I->getOperand(5).getReg();
+ Register OldVal = I->getOperand(6).getReg();
+ Register BinOpRes = I->getOperand(7).getReg();
+ Register StoreVal = I->getOperand(8).getReg();
+
+ const BasicBlock *LLVM_BB = BB.getBasicBlock();
+ MachineBasicBlock *loopMBB = MF->CreateMachineBasicBlock(LLVM_BB);
+ MachineBasicBlock *sinkMBB = MF->CreateMachineBasicBlock(LLVM_BB);
+ MachineBasicBlock *exitMBB = MF->CreateMachineBasicBlock(LLVM_BB);
+ MachineFunction::iterator It = ++BB.getIterator();
+ MF->insert(It, loopMBB);
+ MF->insert(It, sinkMBB);
+ MF->insert(It, exitMBB);
+
+ exitMBB->splice(exitMBB->begin(), &BB, std::next(I), BB.end());
+ exitMBB->transferSuccessorsAndUpdatePHIs(&BB);
+
+ BB.addSuccessor(loopMBB, BranchProbability::getOne());
+ loopMBB->addSuccessor(sinkMBB);
+ loopMBB->addSuccessor(loopMBB);
+ loopMBB->normalizeSuccProbs();
+
+ BuildMI(loopMBB, DL, TII->get(LL), OldVal).addReg(Ptr).addImm(0);
+ if (IsNand) {
+ // and andres, oldval, incr2
+ // nor binopres, $0, andres
+ // and newval, binopres, mask
+ BuildMI(loopMBB, DL, TII->get(Mips::AND), BinOpRes)
+ .addReg(OldVal)
+ .addReg(Incr);
+ BuildMI(loopMBB, DL, TII->get(Mips::NOR), BinOpRes)
+ .addReg(Mips::ZERO)
+ .addReg(BinOpRes);
+ BuildMI(loopMBB, DL, TII->get(Mips::AND), BinOpRes)
+ .addReg(BinOpRes)
+ .addReg(Mask);
+ } else if (IsMin || IsMax) {
+
+ assert(I->getNumOperands() == 10 &&
+ "Atomics min|max|umin|umax use an additional register");
+ Register Scratch4 = I->getOperand(9).getReg();
+
+ unsigned SLTScratch4 = IsUnsigned ? SLTu : SLT;
+ unsigned SELIncr = IsMax ? SELNEZ : SELEQZ;
+ unsigned SELOldVal = IsMax ? SELEQZ : SELNEZ;
+ unsigned MOVIncr = IsMax ? MOVN : MOVZ;
+
+ // For little endian we need to clear uninterested bits.
+ if (STI->isLittle()) {
+ // and OldVal, OldVal, Mask
+ // and Incr, Incr, Mask
+ BuildMI(loopMBB, DL, TII->get(Mips::AND), OldVal)
+ .addReg(OldVal)
+ .addReg(Mask);
+ BuildMI(loopMBB, DL, TII->get(Mips::AND), Incr).addReg(Incr).addReg(Mask);
+ }
+
+ // unsigned: sltu Scratch4, oldVal, Incr
+ // signed: slt Scratch4, oldVal, Incr
+ BuildMI(loopMBB, DL, TII->get(SLTScratch4), Scratch4)
+ .addReg(OldVal)
+ .addReg(Incr);
+
+ if (STI->hasMips64r6() || STI->hasMips32r6()) {
+ // max: seleqz BinOpRes, OldVal, Scratch4
+ // selnez Scratch4, Incr, Scratch4
+ // or BinOpRes, BinOpRes, Scratch4
+ // min: selnqz BinOpRes, OldVal, Scratch4
+ // seleqz Scratch4, Incr, Scratch4
+ // or BinOpRes, BinOpRes, Scratch4
+ BuildMI(loopMBB, DL, TII->get(SELOldVal), BinOpRes)
+ .addReg(OldVal)
+ .addReg(Scratch4);
+ BuildMI(loopMBB, DL, TII->get(SELIncr), Scratch4)
+ .addReg(Incr)
+ .addReg(Scratch4);
+ BuildMI(loopMBB, DL, TII->get(OR), BinOpRes)
+ .addReg(BinOpRes)
+ .addReg(Scratch4);
+ } else {
+ // max: move BinOpRes, OldVal
+ // movn BinOpRes, Incr, Scratch4, BinOpRes
+ // min: move BinOpRes, OldVal
+ // movz BinOpRes, Incr, Scratch4, BinOpRes
+ BuildMI(loopMBB, DL, TII->get(OR), BinOpRes)
+ .addReg(OldVal)
+ .addReg(Mips::ZERO);
+ BuildMI(loopMBB, DL, TII->get(MOVIncr), BinOpRes)
+ .addReg(Incr)
+ .addReg(Scratch4)
+ .addReg(BinOpRes);
+ }
+
+ // and BinOpRes, BinOpRes, Mask
+ BuildMI(loopMBB, DL, TII->get(Mips::AND), BinOpRes)
+ .addReg(BinOpRes)
+ .addReg(Mask);
+
+ } else if (!IsSwap) {
+ // <binop> binopres, oldval, incr2
+ // and newval, binopres, mask
+ BuildMI(loopMBB, DL, TII->get(Opcode), BinOpRes)
+ .addReg(OldVal)
+ .addReg(Incr);
+ BuildMI(loopMBB, DL, TII->get(Mips::AND), BinOpRes)
+ .addReg(BinOpRes)
+ .addReg(Mask);
+ } else { // atomic.swap
+ // and newval, incr2, mask
+ BuildMI(loopMBB, DL, TII->get(Mips::AND), BinOpRes)
+ .addReg(Incr)
+ .addReg(Mask);
+ }
+
+ // and StoreVal, OlddVal, Mask2
+ // or StoreVal, StoreVal, BinOpRes
+ // StoreVal<tied1> = sc StoreVal, 0(Ptr)
+ // beq StoreVal, zero, loopMBB
+ BuildMI(loopMBB, DL, TII->get(Mips::AND), StoreVal)
+ .addReg(OldVal).addReg(Mask2);
+ BuildMI(loopMBB, DL, TII->get(Mips::OR), StoreVal)
+ .addReg(StoreVal).addReg(BinOpRes);
+ BuildMI(loopMBB, DL, TII->get(SC), StoreVal)
+ .addReg(StoreVal).addReg(Ptr).addImm(0);
+ BuildMI(loopMBB, DL, TII->get(BEQ))
+ .addReg(StoreVal).addReg(Mips::ZERO).addMBB(loopMBB);
+
+ // sinkMBB:
+ // and maskedoldval1,oldval,mask
+ // srl srlres,maskedoldval1,shiftamt
+ // sign_extend dest,srlres
+
+ sinkMBB->addSuccessor(exitMBB, BranchProbability::getOne());
+
+ BuildMI(sinkMBB, DL, TII->get(Mips::AND), Dest)
+ .addReg(OldVal).addReg(Mask);
+ BuildMI(sinkMBB, DL, TII->get(Mips::SRLV), Dest)
+ .addReg(Dest).addReg(ShiftAmnt);
+
+ if (STI->hasMips32r2()) {
+ BuildMI(sinkMBB, DL, TII->get(SEOp), Dest).addReg(Dest);
+ } else {
+ const unsigned ShiftImm = SEOp == Mips::SEH ? 16 : 24;
+ BuildMI(sinkMBB, DL, TII->get(Mips::SLL), Dest)
+ .addReg(Dest, RegState::Kill)
+ .addImm(ShiftImm);
+ BuildMI(sinkMBB, DL, TII->get(Mips::SRA), Dest)
+ .addReg(Dest, RegState::Kill)
+ .addImm(ShiftImm);
+ }
+
+ LivePhysRegs LiveRegs;
+ computeAndAddLiveIns(LiveRegs, *loopMBB);
+ computeAndAddLiveIns(LiveRegs, *sinkMBB);
+ computeAndAddLiveIns(LiveRegs, *exitMBB);
+
+ NMBBI = BB.end();
+ I->eraseFromParent();
+
+ return true;
+}
+
+bool MipsExpandPseudo::expandAtomicBinOp(MachineBasicBlock &BB,
+ MachineBasicBlock::iterator I,
+ MachineBasicBlock::iterator &NMBBI,
+ unsigned Size) {
+ MachineFunction *MF = BB.getParent();
+
+ const bool ArePtrs64bit = STI->getABI().ArePtrs64bit();
+ DebugLoc DL = I->getDebugLoc();
+
+ unsigned LL, SC, ZERO, BEQ, SLT, SLTu, OR, MOVN, MOVZ, SELNEZ, SELEQZ;
+
+ if (Size == 4) {
+ if (STI->inMicroMipsMode()) {
+ LL = STI->hasMips32r6() ? Mips::LL_MMR6 : Mips::LL_MM;
+ SC = STI->hasMips32r6() ? Mips::SC_MMR6 : Mips::SC_MM;
+ BEQ = STI->hasMips32r6() ? Mips::BEQC_MMR6 : Mips::BEQ_MM;
+ SLT = Mips::SLT_MM;
+ SLTu = Mips::SLTu_MM;
+ OR = STI->hasMips32r6() ? Mips::OR_MMR6 : Mips::OR_MM;
+ MOVN = Mips::MOVN_I_MM;
+ MOVZ = Mips::MOVZ_I_MM;
+ SELNEZ = STI->hasMips32r6() ? Mips::SELNEZ_MMR6 : Mips::SELNEZ;
+ SELEQZ = STI->hasMips32r6() ? Mips::SELEQZ_MMR6 : Mips::SELEQZ;
+ } else {
+ LL = STI->hasMips32r6()
+ ? (ArePtrs64bit ? Mips::LL64_R6 : Mips::LL_R6)
+ : (ArePtrs64bit ? Mips::LL64 : Mips::LL);
+ SC = STI->hasMips32r6()
+ ? (ArePtrs64bit ? Mips::SC64_R6 : Mips::SC_R6)
+ : (ArePtrs64bit ? Mips::SC64 : Mips::SC);
+ BEQ = Mips::BEQ;
+ SLT = Mips::SLT;
+ SLTu = Mips::SLTu;
+ OR = Mips::OR;
+ MOVN = Mips::MOVN_I_I;
+ MOVZ = Mips::MOVZ_I_I;
+ SELNEZ = Mips::SELNEZ;
+ SELEQZ = Mips::SELEQZ;
+ }
+
+ ZERO = Mips::ZERO;
+ } else {
+ LL = STI->hasMips64r6() ? Mips::LLD_R6 : Mips::LLD;
+ SC = STI->hasMips64r6() ? Mips::SCD_R6 : Mips::SCD;
+ ZERO = Mips::ZERO_64;
+ BEQ = Mips::BEQ64;
+ SLT = Mips::SLT64;
+ SLTu = Mips::SLTu64;
+ OR = Mips::OR64;
+ MOVN = Mips::MOVN_I64_I64;
+ MOVZ = Mips::MOVZ_I64_I64;
+ SELNEZ = Mips::SELNEZ64;
+ SELEQZ = Mips::SELEQZ64;
+ }
+
+ Register OldVal = I->getOperand(0).getReg();
+ Register Ptr = I->getOperand(1).getReg();
+ Register Incr = I->getOperand(2).getReg();
+ Register Scratch = I->getOperand(3).getReg();
+
+ unsigned Opcode = 0;
+ unsigned AND = 0;
+ unsigned NOR = 0;
+
+ bool IsOr = false;
+ bool IsNand = false;
+ bool IsMin = false;
+ bool IsMax = false;
+ bool IsUnsigned = false;
+
+ switch (I->getOpcode()) {
+ case Mips::ATOMIC_LOAD_ADD_I32_POSTRA:
+ Opcode = Mips::ADDu;
+ break;
+ case Mips::ATOMIC_LOAD_SUB_I32_POSTRA:
+ Opcode = Mips::SUBu;
+ break;
+ case Mips::ATOMIC_LOAD_AND_I32_POSTRA:
+ Opcode = Mips::AND;
+ break;
+ case Mips::ATOMIC_LOAD_OR_I32_POSTRA:
+ Opcode = Mips::OR;
+ break;
+ case Mips::ATOMIC_LOAD_XOR_I32_POSTRA:
+ Opcode = Mips::XOR;
+ break;
+ case Mips::ATOMIC_LOAD_NAND_I32_POSTRA:
+ IsNand = true;
+ AND = Mips::AND;
+ NOR = Mips::NOR;
+ break;
+ case Mips::ATOMIC_SWAP_I32_POSTRA:
+ IsOr = true;
+ break;
+ case Mips::ATOMIC_LOAD_ADD_I64_POSTRA:
+ Opcode = Mips::DADDu;
+ break;
+ case Mips::ATOMIC_LOAD_SUB_I64_POSTRA:
+ Opcode = Mips::DSUBu;
+ break;
+ case Mips::ATOMIC_LOAD_AND_I64_POSTRA:
+ Opcode = Mips::AND64;
+ break;
+ case Mips::ATOMIC_LOAD_OR_I64_POSTRA:
+ Opcode = Mips::OR64;
+ break;
+ case Mips::ATOMIC_LOAD_XOR_I64_POSTRA:
+ Opcode = Mips::XOR64;
+ break;
+ case Mips::ATOMIC_LOAD_NAND_I64_POSTRA:
+ IsNand = true;
+ AND = Mips::AND64;
+ NOR = Mips::NOR64;
+ break;
+ case Mips::ATOMIC_SWAP_I64_POSTRA:
+ IsOr = true;
+ break;
+ case Mips::ATOMIC_LOAD_UMIN_I32_POSTRA:
+ case Mips::ATOMIC_LOAD_UMIN_I64_POSTRA:
+ IsUnsigned = true;
+ LLVM_FALLTHROUGH;
+ case Mips::ATOMIC_LOAD_MIN_I32_POSTRA:
+ case Mips::ATOMIC_LOAD_MIN_I64_POSTRA:
+ IsMin = true;
+ break;
+ case Mips::ATOMIC_LOAD_UMAX_I32_POSTRA:
+ case Mips::ATOMIC_LOAD_UMAX_I64_POSTRA:
+ IsUnsigned = true;
+ LLVM_FALLTHROUGH;
+ case Mips::ATOMIC_LOAD_MAX_I32_POSTRA:
+ case Mips::ATOMIC_LOAD_MAX_I64_POSTRA:
+ IsMax = true;
+ break;
+ default:
+ llvm_unreachable("Unknown pseudo atomic!");
+ }
+
+ const BasicBlock *LLVM_BB = BB.getBasicBlock();
+ MachineBasicBlock *loopMBB = MF->CreateMachineBasicBlock(LLVM_BB);
+ MachineBasicBlock *exitMBB = MF->CreateMachineBasicBlock(LLVM_BB);
+ MachineFunction::iterator It = ++BB.getIterator();
+ MF->insert(It, loopMBB);
+ MF->insert(It, exitMBB);
+
+ exitMBB->splice(exitMBB->begin(), &BB, std::next(I), BB.end());
+ exitMBB->transferSuccessorsAndUpdatePHIs(&BB);
+
+ BB.addSuccessor(loopMBB, BranchProbability::getOne());
+ loopMBB->addSuccessor(exitMBB);
+ loopMBB->addSuccessor(loopMBB);
+ loopMBB->normalizeSuccProbs();
+
+ BuildMI(loopMBB, DL, TII->get(LL), OldVal).addReg(Ptr).addImm(0);
+ assert((OldVal != Ptr) && "Clobbered the wrong ptr reg!");
+ assert((OldVal != Incr) && "Clobbered the wrong reg!");
+ if (IsMin || IsMax) {
+
+ assert(I->getNumOperands() == 5 &&
+ "Atomics min|max|umin|umax use an additional register");
+ Register Scratch2 = I->getOperand(4).getReg();
+
+ // On Mips64 result of slt is GPR32.
+ Register Scratch2_32 =
+ (Size == 8) ? STI->getRegisterInfo()->getSubReg(Scratch2, Mips::sub_32)
+ : Scratch2;
+
+ unsigned SLTScratch2 = IsUnsigned ? SLTu : SLT;
+ unsigned SELIncr = IsMax ? SELNEZ : SELEQZ;
+ unsigned SELOldVal = IsMax ? SELEQZ : SELNEZ;
+ unsigned MOVIncr = IsMax ? MOVN : MOVZ;
+
+ // unsigned: sltu Scratch2, oldVal, Incr
+ // signed: slt Scratch2, oldVal, Incr
+ BuildMI(loopMBB, DL, TII->get(SLTScratch2), Scratch2_32)
+ .addReg(OldVal)
+ .addReg(Incr);
+
+ if (STI->hasMips64r6() || STI->hasMips32r6()) {
+ // max: seleqz Scratch, OldVal, Scratch2
+ // selnez Scratch2, Incr, Scratch2
+ // or Scratch, Scratch, Scratch2
+ // min: selnez Scratch, OldVal, Scratch2
+ // seleqz Scratch2, Incr, Scratch2
+ // or Scratch, Scratch, Scratch2
+ BuildMI(loopMBB, DL, TII->get(SELOldVal), Scratch)
+ .addReg(OldVal)
+ .addReg(Scratch2);
+ BuildMI(loopMBB, DL, TII->get(SELIncr), Scratch2)
+ .addReg(Incr)
+ .addReg(Scratch2);
+ BuildMI(loopMBB, DL, TII->get(OR), Scratch)
+ .addReg(Scratch)
+ .addReg(Scratch2);
+ } else {
+ // max: move Scratch, OldVal
+ // movn Scratch, Incr, Scratch2, Scratch
+ // min: move Scratch, OldVal
+ // movz Scratch, Incr, Scratch2, Scratch
+ BuildMI(loopMBB, DL, TII->get(OR), Scratch)
+ .addReg(OldVal)
+ .addReg(ZERO);
+ BuildMI(loopMBB, DL, TII->get(MOVIncr), Scratch)
+ .addReg(Incr)
+ .addReg(Scratch2)
+ .addReg(Scratch);
+ }
+
+ } else if (Opcode) {
+ BuildMI(loopMBB, DL, TII->get(Opcode), Scratch).addReg(OldVal).addReg(Incr);
+ } else if (IsNand) {
+ assert(AND && NOR &&
+ "Unknown nand instruction for atomic pseudo expansion");
+ BuildMI(loopMBB, DL, TII->get(AND), Scratch).addReg(OldVal).addReg(Incr);
+ BuildMI(loopMBB, DL, TII->get(NOR), Scratch).addReg(ZERO).addReg(Scratch);
+ } else {
+ assert(IsOr && OR && "Unknown instruction for atomic pseudo expansion!");
+ (void)IsOr;
+ BuildMI(loopMBB, DL, TII->get(OR), Scratch).addReg(Incr).addReg(ZERO);
+ }
+
+ BuildMI(loopMBB, DL, TII->get(SC), Scratch)
+ .addReg(Scratch)
+ .addReg(Ptr)
+ .addImm(0);
+ BuildMI(loopMBB, DL, TII->get(BEQ))
+ .addReg(Scratch)
+ .addReg(ZERO)
+ .addMBB(loopMBB);
+
+ NMBBI = BB.end();
+ I->eraseFromParent();
+
+ LivePhysRegs LiveRegs;
+ computeAndAddLiveIns(LiveRegs, *loopMBB);
+ computeAndAddLiveIns(LiveRegs, *exitMBB);
+
+ return true;
+}
+
+bool MipsExpandPseudo::expandMI(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MBBI,
+ MachineBasicBlock::iterator &NMBB) {
+
+ bool Modified = false;
+
+ switch (MBBI->getOpcode()) {
+ case Mips::ATOMIC_CMP_SWAP_I32_POSTRA:
+ case Mips::ATOMIC_CMP_SWAP_I64_POSTRA:
+ return expandAtomicCmpSwap(MBB, MBBI, NMBB);
+ case Mips::ATOMIC_CMP_SWAP_I8_POSTRA:
+ case Mips::ATOMIC_CMP_SWAP_I16_POSTRA:
+ return expandAtomicCmpSwapSubword(MBB, MBBI, NMBB);
+ case Mips::ATOMIC_SWAP_I8_POSTRA:
+ case Mips::ATOMIC_SWAP_I16_POSTRA:
+ case Mips::ATOMIC_LOAD_NAND_I8_POSTRA:
+ case Mips::ATOMIC_LOAD_NAND_I16_POSTRA:
+ case Mips::ATOMIC_LOAD_ADD_I8_POSTRA:
+ case Mips::ATOMIC_LOAD_ADD_I16_POSTRA:
+ case Mips::ATOMIC_LOAD_SUB_I8_POSTRA:
+ case Mips::ATOMIC_LOAD_SUB_I16_POSTRA:
+ case Mips::ATOMIC_LOAD_AND_I8_POSTRA:
+ case Mips::ATOMIC_LOAD_AND_I16_POSTRA:
+ case Mips::ATOMIC_LOAD_OR_I8_POSTRA:
+ case Mips::ATOMIC_LOAD_OR_I16_POSTRA:
+ case Mips::ATOMIC_LOAD_XOR_I8_POSTRA:
+ case Mips::ATOMIC_LOAD_XOR_I16_POSTRA:
+ case Mips::ATOMIC_LOAD_MIN_I8_POSTRA:
+ case Mips::ATOMIC_LOAD_MIN_I16_POSTRA:
+ case Mips::ATOMIC_LOAD_MAX_I8_POSTRA:
+ case Mips::ATOMIC_LOAD_MAX_I16_POSTRA:
+ case Mips::ATOMIC_LOAD_UMIN_I8_POSTRA:
+ case Mips::ATOMIC_LOAD_UMIN_I16_POSTRA:
+ case Mips::ATOMIC_LOAD_UMAX_I8_POSTRA:
+ case Mips::ATOMIC_LOAD_UMAX_I16_POSTRA:
+ return expandAtomicBinOpSubword(MBB, MBBI, NMBB);
+ case Mips::ATOMIC_LOAD_ADD_I32_POSTRA:
+ case Mips::ATOMIC_LOAD_SUB_I32_POSTRA:
+ case Mips::ATOMIC_LOAD_AND_I32_POSTRA:
+ case Mips::ATOMIC_LOAD_OR_I32_POSTRA:
+ case Mips::ATOMIC_LOAD_XOR_I32_POSTRA:
+ case Mips::ATOMIC_LOAD_NAND_I32_POSTRA:
+ case Mips::ATOMIC_SWAP_I32_POSTRA:
+ case Mips::ATOMIC_LOAD_MIN_I32_POSTRA:
+ case Mips::ATOMIC_LOAD_MAX_I32_POSTRA:
+ case Mips::ATOMIC_LOAD_UMIN_I32_POSTRA:
+ case Mips::ATOMIC_LOAD_UMAX_I32_POSTRA:
+ return expandAtomicBinOp(MBB, MBBI, NMBB, 4);
+ case Mips::ATOMIC_LOAD_ADD_I64_POSTRA:
+ case Mips::ATOMIC_LOAD_SUB_I64_POSTRA:
+ case Mips::ATOMIC_LOAD_AND_I64_POSTRA:
+ case Mips::ATOMIC_LOAD_OR_I64_POSTRA:
+ case Mips::ATOMIC_LOAD_XOR_I64_POSTRA:
+ case Mips::ATOMIC_LOAD_NAND_I64_POSTRA:
+ case Mips::ATOMIC_SWAP_I64_POSTRA:
+ case Mips::ATOMIC_LOAD_MIN_I64_POSTRA:
+ case Mips::ATOMIC_LOAD_MAX_I64_POSTRA:
+ case Mips::ATOMIC_LOAD_UMIN_I64_POSTRA:
+ case Mips::ATOMIC_LOAD_UMAX_I64_POSTRA:
+ return expandAtomicBinOp(MBB, MBBI, NMBB, 8);
+ default:
+ return Modified;
+ }
+}
+
+bool MipsExpandPseudo::expandMBB(MachineBasicBlock &MBB) {
+ bool Modified = false;
+
+ MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
+ while (MBBI != E) {
+ MachineBasicBlock::iterator NMBBI = std::next(MBBI);
+ Modified |= expandMI(MBB, MBBI, NMBBI);
+ MBBI = NMBBI;
+ }
+
+ return Modified;
+}
+
+bool MipsExpandPseudo::runOnMachineFunction(MachineFunction &MF) {
+ STI = &static_cast<const MipsSubtarget &>(MF.getSubtarget());
+ TII = STI->getInstrInfo();
+
+ bool Modified = false;
+ for (MachineFunction::iterator MFI = MF.begin(), E = MF.end(); MFI != E;
+ ++MFI)
+ Modified |= expandMBB(*MFI);
+
+ if (Modified)
+ MF.RenumberBlocks();
+
+ return Modified;
+}
+
+/// createMipsExpandPseudoPass - returns an instance of the pseudo instruction
+/// expansion pass.
+FunctionPass *llvm::createMipsExpandPseudoPass() {
+ return new MipsExpandPseudo();
+}