forked from OSchip/llvm-project
702 lines
23 KiB
C++
702 lines
23 KiB
C++
//===-- 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);
|
|
}
|
|
|
|
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();
|
|
}
|