703 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			703 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===-- 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();
 | |
| }
 |