#include "PPCInstrInfo.h"
#include "MCTargetDesc/PPCPredicates.h"
#include "PPC.h"
#include "PPCHazardRecognizers.h"
#include "PPCInstrBuilder.h"
#include "PPCMachineFunctionInfo.h"
#include "PPCTargetMachine.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineMemOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
#define DEBUG_TYPE "ppc-vsx-copy"
namespace llvm {
void initializePPCVSXCopyPass(PassRegistry&);
}
namespace {
struct PPCVSXCopy : public MachineFunctionPass {
static char ID;
PPCVSXCopy() : MachineFunctionPass(ID) {
initializePPCVSXCopyPass(*PassRegistry::getPassRegistry());
}
const TargetInstrInfo *TII;
bool IsRegInClass(unsigned Reg, const TargetRegisterClass *RC,
MachineRegisterInfo &MRI) {
if (TargetRegisterInfo::isVirtualRegister(Reg)) {
return RC->hasSubClassEq(MRI.getRegClass(Reg));
} else if (RC->contains(Reg)) {
return true;
}
return false;
}
bool IsVSReg(unsigned Reg, MachineRegisterInfo &MRI) {
return IsRegInClass(Reg, &PPC::VSRCRegClass, MRI);
}
bool IsVRReg(unsigned Reg, MachineRegisterInfo &MRI) {
return IsRegInClass(Reg, &PPC::VRRCRegClass, MRI);
}
bool IsF8Reg(unsigned Reg, MachineRegisterInfo &MRI) {
return IsRegInClass(Reg, &PPC::F8RCRegClass, MRI);
}
protected:
bool processBlock(MachineBasicBlock &MBB) {
bool Changed = false;
MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
for (MachineBasicBlock::iterator I = MBB.begin(), IE = MBB.end();
I != IE; ++I) {
MachineInstr *MI = I;
if (!MI->isFullCopy())
continue;
MachineOperand &DstMO = MI->getOperand(0);
MachineOperand &SrcMO = MI->getOperand(1);
if ( IsVSReg(DstMO.getReg(), MRI) &&
!IsVSReg(SrcMO.getReg(), MRI)) {
Changed = true;
const TargetRegisterClass *SrcRC =
IsVRReg(SrcMO.getReg(), MRI) ? &PPC::VSHRCRegClass :
&PPC::VSLRCRegClass;
assert((IsF8Reg(SrcMO.getReg(), MRI) ||
IsVRReg(SrcMO.getReg(), MRI)) &&
"Unknown source for a VSX copy");
unsigned NewVReg = MRI.createVirtualRegister(SrcRC);
BuildMI(MBB, MI, MI->getDebugLoc(),
TII->get(TargetOpcode::SUBREG_TO_REG), NewVReg)
.addImm(1) .addOperand(SrcMO)
.addImm(IsVRReg(SrcMO.getReg(), MRI) ? PPC::sub_128 :
PPC::sub_64);
SrcMO.setReg(NewVReg);
} else if (!IsVSReg(DstMO.getReg(), MRI) &&
IsVSReg(SrcMO.getReg(), MRI)) {
Changed = true;
const TargetRegisterClass *DstRC =
IsVRReg(DstMO.getReg(), MRI) ? &PPC::VSHRCRegClass :
&PPC::VSLRCRegClass;
assert((IsF8Reg(DstMO.getReg(), MRI) ||
IsVRReg(DstMO.getReg(), MRI)) &&
"Unknown destination for a VSX copy");
unsigned NewVReg = MRI.createVirtualRegister(DstRC);
BuildMI(MBB, MI, MI->getDebugLoc(),
TII->get(TargetOpcode::COPY), NewVReg)
.addOperand(SrcMO);
SrcMO.setReg(NewVReg);
SrcMO.setSubReg(IsVRReg(DstMO.getReg(), MRI) ? PPC::sub_128 :
PPC::sub_64);
}
}
return Changed;
}
public:
bool runOnMachineFunction(MachineFunction &MF) override {
const PPCSubtarget &STI = MF.getSubtarget<PPCSubtarget>();
if (!STI.hasVSX())
return false;
TII = STI.getInstrInfo();
bool Changed = false;
for (MachineFunction::iterator I = MF.begin(); I != MF.end();) {
MachineBasicBlock &B = *I++;
if (processBlock(B))
Changed = true;
}
return Changed;
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
MachineFunctionPass::getAnalysisUsage(AU);
}
};
}
INITIALIZE_PASS(PPCVSXCopy, DEBUG_TYPE,
"PowerPC VSX Copy Legalization", false, false)
char PPCVSXCopy::ID = 0;
FunctionPass*
llvm::createPPCVSXCopyPass() { return new PPCVSXCopy(); }