60 #define DEBUG_TYPE "ppc-vsx-swaps"
70 struct PPCVSXSwapEntry {
78 unsigned int IsLoad : 1;
79 unsigned int IsStore : 1;
80 unsigned int IsSwap : 1;
81 unsigned int MentionsPhysVR : 1;
82 unsigned int IsSwappable : 1;
83 unsigned int MentionsPartialVR : 1;
84 unsigned int SpecialHandling : 3;
85 unsigned int WebRejected : 1;
86 unsigned int WillRemove : 1;
108 std::vector<PPCVSXSwapEntry> SwapVector;
128 bool gatherVectorInstructions();
137 unsigned lookThruCopyLike(
unsigned SrcReg,
unsigned VecIdx);
143 void recordUnoptimizableWebs();
146 void markSwapsForRemoval();
153 void handleSpecialSwappables(
int EntryIdx);
156 void dumpSwapVector();
168 bool isVecReg(
unsigned Reg) {
169 return (isRegInClass(Reg, &PPC::VSRCRegClass) ||
170 isRegInClass(Reg, &PPC::VRRCRegClass));
174 bool isScalarVecReg(
unsigned Reg) {
175 return (isRegInClass(Reg, &PPC::VSFRCRegClass) ||
176 isRegInClass(Reg, &PPC::VSSRCRegClass));
182 bool isAnyVecReg(
unsigned Reg,
bool &Partial) {
183 if (isScalarVecReg(Reg))
185 return isScalarVecReg(Reg) || isVecReg(Reg);
196 bool Changed =
false;
199 if (gatherVectorInstructions()) {
201 recordUnoptimizableWebs();
202 markSwapsForRemoval();
203 Changed = removeSwaps();
224 const int InitialVectorSize(256);
226 SwapVector.reserve(InitialVectorSize);
237 bool PPCVSXSwapRemoval::gatherVectorInstructions() {
238 bool RelevantFunction =
false;
243 bool RelevantInstr =
false;
244 bool Partial =
false;
249 unsigned Reg = MO.getReg();
250 if (isAnyVecReg(Reg, Partial)) {
251 RelevantInstr =
true;
259 RelevantFunction =
true;
264 PPCVSXSwapEntry SwapEntry{};
265 int VecIdx = addSwapEntry(&
MI, SwapEntry);
267 switch(
MI.getOpcode()) {
276 SwapVector[VecIdx].MentionsPartialVR = 1;
278 SwapVector[VecIdx].IsSwappable = 1;
280 case PPC::XXPERMDI: {
288 int immed =
MI.getOperand(3).getImm();
290 unsigned trueReg1 = lookThruCopyLike(
MI.getOperand(1).getReg(),
292 unsigned trueReg2 = lookThruCopyLike(
MI.getOperand(2).getReg(),
294 if (trueReg1 == trueReg2)
295 SwapVector[VecIdx].IsSwap = 1;
299 SwapVector[VecIdx].IsSwappable = 1;
300 SwapVector[VecIdx].SpecialHandling = SHValues::SH_XXPERMDI;
310 }
else if (immed == 0 || immed == 3) {
312 SwapVector[VecIdx].IsSwappable = 1;
313 SwapVector[VecIdx].SpecialHandling = SHValues::SH_XXPERMDI;
315 unsigned trueReg1 = lookThruCopyLike(
MI.getOperand(1).getReg(),
317 unsigned trueReg2 = lookThruCopyLike(
MI.getOperand(2).getReg(),
319 if (trueReg1 == trueReg2)
320 SwapVector[VecIdx].MentionsPhysVR = 0;
324 SwapVector[VecIdx].IsSwappable = 1;
325 SwapVector[VecIdx].SpecialHandling = SHValues::SH_XXPERMDI;
334 SwapVector[VecIdx].IsLoad = 1;
340 SwapVector[VecIdx].IsLoad = 1;
341 SwapVector[VecIdx].IsSwap = 1;
348 SwapVector[VecIdx].IsStore = 1;
354 SwapVector[VecIdx].IsStore = 1;
355 SwapVector[VecIdx].IsSwap = 1;
360 if (isVecReg(
MI.getOperand(0).getReg()) &&
361 isVecReg(
MI.getOperand(1).getReg()))
362 SwapVector[VecIdx].IsSwappable = 1;
367 else if (isScalarVecReg(
MI.getOperand(0).getReg()) &&
368 isScalarVecReg(
MI.getOperand(1).getReg()))
369 SwapVector[VecIdx].IsSwappable = 1;
379 if (isVecReg(
MI.getOperand(0).getReg()) &&
380 isVecReg(
MI.getOperand(2).getReg()))
381 SwapVector[VecIdx].IsSwappable = 1;
382 else if (isVecReg(
MI.getOperand(0).getReg()) &&
383 isScalarVecReg(
MI.getOperand(2).getReg())) {
384 SwapVector[VecIdx].IsSwappable = 1;
385 SwapVector[VecIdx].SpecialHandling = SHValues::SH_COPYSCALAR;
395 SwapVector[VecIdx].IsSwappable = 1;
396 SwapVector[VecIdx].SpecialHandling = SHValues::SH_SPLAT;
422 case PPC::VCIPHERLAST:
442 case PPC::VNCIPHERLAST:
467 case PPC::VSHASIGMAD:
468 case PPC::VSHASIGMAW:
499 if (RelevantFunction) {
500 DEBUG(
dbgs() <<
"Swap vector when first built\n\n");
504 return RelevantFunction;
510 PPCVSXSwapEntry& SwapEntry) {
511 SwapEntry.VSEMI =
MI;
512 SwapEntry.VSEId = SwapVector.size();
513 SwapVector.push_back(SwapEntry);
514 EC->insert(SwapEntry.VSEId);
515 SwapMap[
MI] = SwapEntry.VSEId;
516 return SwapEntry.VSEId;
528 unsigned PPCVSXSwapRemoval::lookThruCopyLike(
unsigned SrcReg,
538 assert(MI->
isSubregToReg() &&
"bad opcode for lookThruCopyLike");
543 SwapVector[VecIdx].MentionsPhysVR = 1;
547 return lookThruCopyLike(CopySrcReg, VecIdx);
557 void PPCVSXSwapRemoval::formWebs() {
559 DEBUG(
dbgs() <<
"\n*** Forming webs for swap removal ***\n\n");
561 for (
unsigned EntryIdx = 0; EntryIdx < SwapVector.size(); ++EntryIdx) {
565 DEBUG(
dbgs() <<
"\n" << SwapVector[EntryIdx].VSEId <<
" ");
576 unsigned Reg = MO.getReg();
577 if (!isVecReg(Reg) && !isScalarVecReg(Reg))
581 if (!(MI->
isCopy() && isScalarVecReg(Reg)))
582 SwapVector[EntryIdx].MentionsPhysVR = 1;
590 assert(SwapMap.find(DefMI) != SwapMap.end() &&
591 "Inconsistency: def of vector reg not found in swap map!");
592 int DefIdx = SwapMap[DefMI];
593 (void)EC->unionSets(SwapVector[DefIdx].VSEId,
594 SwapVector[EntryIdx].VSEId);
596 DEBUG(
dbgs() <<
format(
"Unioning %d with %d\n", SwapVector[DefIdx].VSEId,
597 SwapVector[EntryIdx].VSEId));
608 void PPCVSXSwapRemoval::recordUnoptimizableWebs() {
610 DEBUG(
dbgs() <<
"\n*** Rejecting webs for swap removal ***\n\n");
612 for (
unsigned EntryIdx = 0; EntryIdx < SwapVector.size(); ++EntryIdx) {
613 int Repr = EC->getLeaderValue(SwapVector[EntryIdx].VSEId);
616 if (SwapVector[Repr].WebRejected)
622 if (SwapVector[EntryIdx].MentionsPhysVR ||
623 SwapVector[EntryIdx].MentionsPartialVR ||
624 !(SwapVector[EntryIdx].IsSwappable || SwapVector[EntryIdx].IsSwap)) {
626 SwapVector[Repr].WebRejected = 1;
629 format(
"Web %d rejected for physreg, partial reg, or not swap[pable]\n",
631 DEBUG(
dbgs() <<
" in " << EntryIdx <<
": ");
632 DEBUG(SwapVector[EntryIdx].VSEMI->dump());
638 else if (SwapVector[EntryIdx].IsLoad && SwapVector[EntryIdx].IsSwap) {
646 for (
MachineInstr &UseMI : MRI->use_nodbg_instructions(DefReg)) {
647 int UseIdx = SwapMap[&UseMI];
649 if (!SwapVector[UseIdx].IsSwap || SwapVector[UseIdx].IsLoad ||
650 SwapVector[UseIdx].IsStore) {
652 SwapVector[Repr].WebRejected = 1;
655 format(
"Web %d rejected for load not feeding swap\n", Repr));
656 DEBUG(
dbgs() <<
" def " << EntryIdx <<
": ");
658 DEBUG(
dbgs() <<
" use " << UseIdx <<
": ");
666 }
else if (SwapVector[EntryIdx].IsStore && SwapVector[EntryIdx].IsSwap) {
670 int DefIdx = SwapMap[DefMI];
672 if (!SwapVector[DefIdx].IsSwap || SwapVector[DefIdx].IsLoad ||
673 SwapVector[DefIdx].IsStore) {
675 SwapVector[Repr].WebRejected = 1;
678 format(
"Web %d rejected for store not fed by swap\n", Repr));
679 DEBUG(
dbgs() <<
" def " << DefIdx <<
": ");
681 DEBUG(
dbgs() <<
" use " << EntryIdx <<
": ");
688 DEBUG(
dbgs() <<
"Swap vector after web analysis:\n\n");
697 void PPCVSXSwapRemoval::markSwapsForRemoval() {
699 DEBUG(
dbgs() <<
"\n*** Marking swaps for removal ***\n\n");
701 for (
unsigned EntryIdx = 0; EntryIdx < SwapVector.size(); ++EntryIdx) {
703 if (SwapVector[EntryIdx].IsLoad && SwapVector[EntryIdx].IsSwap) {
704 int Repr = EC->getLeaderValue(SwapVector[EntryIdx].VSEId);
706 if (!SwapVector[Repr].WebRejected) {
710 for (
MachineInstr &UseMI : MRI->use_nodbg_instructions(DefReg)) {
711 int UseIdx = SwapMap[&UseMI];
712 SwapVector[UseIdx].WillRemove = 1;
714 DEBUG(
dbgs() <<
"Marking swap fed by load for removal: ");
719 }
else if (SwapVector[EntryIdx].IsStore && SwapVector[EntryIdx].IsSwap) {
720 int Repr = EC->getLeaderValue(SwapVector[EntryIdx].VSEId);
722 if (!SwapVector[Repr].WebRejected) {
726 int DefIdx = SwapMap[DefMI];
727 SwapVector[DefIdx].WillRemove = 1;
729 DEBUG(
dbgs() <<
"Marking swap feeding store for removal: ");
733 }
else if (SwapVector[EntryIdx].IsSwappable &&
734 SwapVector[EntryIdx].SpecialHandling != 0) {
735 int Repr = EC->getLeaderValue(SwapVector[EntryIdx].VSEId);
737 if (!SwapVector[Repr].WebRejected)
738 handleSpecialSwappables(EntryIdx);
748 void PPCVSXSwapRemoval::handleSpecialSwappables(
int EntryIdx) {
749 switch (SwapVector[EntryIdx].SpecialHandling) {
752 assert(
false &&
"Unexpected special handling type");
757 case SHValues::SH_SPLAT: {
766 assert(
false &&
"Unexpected splat opcode");
767 case PPC::VSPLTB: NElts = 16;
break;
768 case PPC::VSPLTH: NElts = 8;
break;
769 case PPC::VSPLTW: NElts = 4;
break;
773 EltNo = (EltNo + NElts / 2) % NElts;
787 case SHValues::SH_XXPERMDI: {
794 if (Selector == 0 || Selector == 3)
795 Selector = 3 - Selector;
811 case SHValues::SH_COPYSCALAR: {
814 DEBUG(
dbgs() <<
"Changing SUBREG_TO_REG: ");
819 unsigned NewVReg = MRI->createVirtualRegister(DstRC);
833 if (DstRC == &PPC::VRRCRegClass) {
834 unsigned VSRCTmp1 = MRI->createVirtualRegister(&PPC::VSRCRegClass);
835 unsigned VSRCTmp2 = MRI->createVirtualRegister(&PPC::VSRCRegClass);
843 TII->get(PPC::XXPERMDI), VSRCTmp2)
857 TII->get(PPC::XXPERMDI), DstReg)
871 bool PPCVSXSwapRemoval::removeSwaps() {
873 DEBUG(
dbgs() <<
"\n*** Removing swaps ***\n\n");
875 bool Changed =
false;
877 for (
unsigned EntryIdx = 0; EntryIdx < SwapVector.size(); ++EntryIdx) {
878 if (SwapVector[EntryIdx].WillRemove) {
887 SwapVector[EntryIdx].VSEId));
898 void PPCVSXSwapRemoval::dumpSwapVector() {
900 for (
unsigned EntryIdx = 0; EntryIdx < SwapVector.size(); ++EntryIdx) {
903 int ID = SwapVector[EntryIdx].VSEId;
910 if (SwapVector[EntryIdx].IsLoad)
912 if (SwapVector[EntryIdx].IsStore)
914 if (SwapVector[EntryIdx].IsSwap)
916 if (SwapVector[EntryIdx].MentionsPhysVR)
918 if (SwapVector[EntryIdx].MentionsPartialVR)
921 if (SwapVector[EntryIdx].IsSwappable) {
923 switch(SwapVector[EntryIdx].SpecialHandling) {
953 if (SwapVector[EntryIdx].WebRejected)
955 if (SwapVector[EntryIdx].WillRemove)
971 "PowerPC VSX Swap Removal",
false,
false)
975 char PPCVSXSwapRemoval::ID = 0;
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
FunctionPass * createPPCVSXSwapRemovalPass()
int getNumber() const
getNumber - MachineBasicBlocks are uniquely numbered at the function level, unless they're not in a M...
bool hasSubClassEq(const TargetRegisterClass *RC) const
hasSubClassEq - Returns true if RC is a sub-class of or equal to this class.
static bool isVirtualRegister(unsigned Reg)
isVirtualRegister - Return true if the specified register number is in the virtual register namespace...
iterator_range< mop_iterator > operands()
COPY - Target-independent register copy.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
const HexagonInstrInfo * TII
NodeTy * getNextNode()
Get the next node, or 0 for the list tail.
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
void eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
Reg
All possible values of the reg field in the ModR/M byte.
const MachineInstrBuilder & addImm(int64_t Val) const
addImm - Add a new immediate operand.
INLINEASM - Represents an inline asm block.
bool isCopyLike() const
Return true if the instruction behaves like a copy.
CHAIN = STXVD2X CHAIN, VSRC, Ptr - Occurs only for little endian.
void initializePPCVSXSwapRemovalPass(PassRegistry &)
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineBasicBlock * getParent() const
format_object< Ts...> format(const char *Fmt, const Ts &...Vals)
These are helper functions used to produce formatted output.
VSRC, CHAIN = LXVD2X_LE CHAIN, Ptr - Occurs only for little endian.
bundle_iterator< MachineInstr, instr_iterator > iterator
const MachineOperand & getOperand(unsigned i) const
INSERT_SUBREG - This instruction takes three operands: a register that has subregisters, a register providing an insert value, and a subregister index.
EquivalenceClasses - This represents a collection of equivalence classes and supports three efficient...
void setImm(int64_t immVal)
FunctionPass class - This class is used to implement most global optimizations.
MachineInstrBuilder BuildMI(MachineFunction &MF, DebugLoc DL, const MCInstrDesc &MCID)
BuildMI - Builder interface.
static void initialize(TargetLibraryInfoImpl &TLI, const Triple &T, const char *const *StandardNames)
initialize - Initialize the set of available library functions based on the specified target triple...
EXTRACT_SUBREG - This instruction takes two operands: a register that has subregisters, and a subregister index.
MachineOperand class - Representation of each machine instruction operand.
VPERM - The PPC VPERM Instruction.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool isSubregToReg() const
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
MachineRegisterInfo - Keep track of information for virtual and physical registers, including vreg register classes, use/def chains for registers, etc.
Representation of each machine instruction.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
static unsigned UseReg(const MachineOperand &MO)
void setReg(unsigned Reg)
Change the register this operand corresponds to.
COPY_TO_REGCLASS - This instruction is a placeholder for a plain register-to-register copy into a spe...
unsigned getReg() const
getReg - Returns the register number.
INITIALIZE_PASS_BEGIN(PPCVSXSwapRemoval, DEBUG_TYPE,"PowerPC VSX Swap Removal", false, false) INITIALIZE_PASS_END(PPCVSXSwapRemoval
virtual const TargetInstrInfo * getInstrInfo() const
PassRegistry - This class manages the registration and intitialization of the pass subsystem as appli...
SUBREG_TO_REG - This instruction is similar to INSERT_SUBREG except that the first operand is an imme...
const MachineInstrBuilder & addReg(unsigned RegNo, unsigned flags=0, unsigned SubReg=0) const
addReg - Add a new virtual register operand...
bool contains(unsigned Reg) const
contains - Return true if the specified register is included in this register class.