| //===-- MipsExpandPseudoInsts.cpp - Expand pseudo instructions ------------===// | |
| // | |
| // The LLVM Compiler Infrastructure | |
| // | |
| // This file is distributed under the University of Illinois Open Source | |
| // License. See LICENSE.TXT for details. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // 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); | |
| } | |
| unsigned Dest = I->getOperand(0).getReg(); | |
| unsigned Ptr = I->getOperand(1).getReg(); | |
| unsigned Mask = I->getOperand(2).getReg(); | |
| unsigned ShiftCmpVal = I->getOperand(3).getReg(); | |
| unsigned Mask2 = I->getOperand(4).getReg(); | |
| unsigned ShiftNewVal = I->getOperand(5).getReg(); | |
| unsigned ShiftAmnt = I->getOperand(6).getReg(); | |
| unsigned Scratch = I->getOperand(7).getReg(); | |
| unsigned 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; | |
| } | |
| unsigned Dest = I->getOperand(0).getReg(); | |
| unsigned Ptr = I->getOperand(1).getReg(); | |
| unsigned OldVal = I->getOperand(2).getReg(); | |
| unsigned NewVal = I->getOperand(3).getReg(); | |
| unsigned 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; | |
| 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; | |
| } 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); | |
| } | |
| bool IsSwap = false; | |
| bool IsNand = 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; | |
| default: | |
| llvm_unreachable("Unknown subword atomic pseudo for expansion!"); | |
| } | |
| unsigned Dest = I->getOperand(0).getReg(); | |
| unsigned Ptr = I->getOperand(1).getReg(); | |
| unsigned Incr = I->getOperand(2).getReg(); | |
| unsigned Mask = I->getOperand(3).getReg(); | |
| unsigned Mask2 = I->getOperand(4).getReg(); | |
| unsigned ShiftAmnt = I->getOperand(5).getReg(); | |
| unsigned OldVal = I->getOperand(6).getReg(); | |
| unsigned BinOpRes = I->getOperand(7).getReg(); | |
| unsigned 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 (!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; | |
| 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; | |
| } 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; | |
| } | |
| 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; | |
| } | |
| unsigned OldVal = I->getOperand(0).getReg(); | |
| unsigned Ptr = I->getOperand(1).getReg(); | |
| unsigned Incr = I->getOperand(2).getReg(); | |
| unsigned Scratch = I->getOperand(3).getReg(); | |
| unsigned Opcode = 0; | |
| unsigned OR = 0; | |
| unsigned AND = 0; | |
| unsigned NOR = 0; | |
| bool IsNand = 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: | |
| OR = Mips::OR; | |
| 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: | |
| OR = Mips::OR64; | |
| 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 (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(OR && "Unknown instruction for atomic pseudo expansion!"); | |
| 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: | |
| 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: | |
| 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: | |
| 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(); | |
| } |