mirror of
https://github.com/RPCS3/llvm.git
synced 2025-01-10 22:46:25 +00:00
[Machine Combiner] Refactor machine reassociation code to be target-independent.
No functional change intended. Patch by Haicheng Wu <haicheng@codeaurora.org>! http://reviews.llvm.org/D12887 PR24522 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@248164 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
7dfb31c329
commit
c5d4530d42
@ -22,7 +22,29 @@ namespace llvm {
|
|||||||
///
|
///
|
||||||
namespace MachineCombinerPattern {
|
namespace MachineCombinerPattern {
|
||||||
// Forward declaration
|
// Forward declaration
|
||||||
enum MC_PATTERN : int;
|
enum MC_PATTERN : int {
|
||||||
|
// These are commutative variants for reassociating a computation chain. See
|
||||||
|
// the comments before getMachineCombinerPatterns() in TargetInstrInfo.cpp.
|
||||||
|
MC_REASSOC_AX_BY = 0,
|
||||||
|
MC_REASSOC_AX_YB = 1,
|
||||||
|
MC_REASSOC_XA_BY = 2,
|
||||||
|
MC_REASSOC_XA_YB = 3,
|
||||||
|
|
||||||
|
/// Enumeration of instruction pattern supported by AArch64 machine combiner
|
||||||
|
MC_NONE,
|
||||||
|
MC_MULADDW_OP1,
|
||||||
|
MC_MULADDW_OP2,
|
||||||
|
MC_MULSUBW_OP1,
|
||||||
|
MC_MULSUBW_OP2,
|
||||||
|
MC_MULADDWI_OP1,
|
||||||
|
MC_MULSUBWI_OP1,
|
||||||
|
MC_MULADDX_OP1,
|
||||||
|
MC_MULADDX_OP2,
|
||||||
|
MC_MULSUBX_OP1,
|
||||||
|
MC_MULSUBX_OP2,
|
||||||
|
MC_MULADDXI_OP1,
|
||||||
|
MC_MULSUBXI_OP1
|
||||||
|
};
|
||||||
} // end namespace MachineCombinerPattern
|
} // end namespace MachineCombinerPattern
|
||||||
} // end namespace llvm
|
} // end namespace llvm
|
||||||
|
|
||||||
|
@ -727,10 +727,27 @@ public:
|
|||||||
/// \param Pattern - Vector of possible combination patterns
|
/// \param Pattern - Vector of possible combination patterns
|
||||||
virtual bool getMachineCombinerPatterns(
|
virtual bool getMachineCombinerPatterns(
|
||||||
MachineInstr &Root,
|
MachineInstr &Root,
|
||||||
SmallVectorImpl<MachineCombinerPattern::MC_PATTERN> &Pattern) const {
|
SmallVectorImpl<MachineCombinerPattern::MC_PATTERN> &Patterns) const;
|
||||||
|
|
||||||
|
/// Return true if the input \P Inst is part of a chain of dependent ops
|
||||||
|
/// that are suitable for reassociation, otherwise return false.
|
||||||
|
/// If the instruction's operands must be commuted to have a previous
|
||||||
|
/// instruction of the same type define the first source operand, \P Commuted
|
||||||
|
/// will be set to true.
|
||||||
|
bool isReassociationCandidate(const MachineInstr &Inst, bool &Commuted) const;
|
||||||
|
|
||||||
|
/// Return true when \P Inst is both associative and commutative.
|
||||||
|
virtual bool isAssociativeAndCommutative(const MachineInstr &Inst) const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return true when \P Inst has reassociable operands in the same \P MBB.
|
||||||
|
virtual bool hasReassociableOperands(const MachineInstr &Inst,
|
||||||
|
const MachineBasicBlock *MBB) const;
|
||||||
|
|
||||||
|
/// Return true when \P Inst has reassociable sibling.
|
||||||
|
bool hasReassociableSibling(const MachineInstr &Inst, bool &Commuted) const;
|
||||||
|
|
||||||
/// When getMachineCombinerPatterns() finds patterns, this function generates
|
/// When getMachineCombinerPatterns() finds patterns, this function generates
|
||||||
/// the instructions that could replace the original code sequence. The client
|
/// the instructions that could replace the original code sequence. The client
|
||||||
/// has to decide whether the actual replacement is beneficial or not.
|
/// has to decide whether the actual replacement is beneficial or not.
|
||||||
@ -745,9 +762,23 @@ public:
|
|||||||
MachineInstr &Root, MachineCombinerPattern::MC_PATTERN Pattern,
|
MachineInstr &Root, MachineCombinerPattern::MC_PATTERN Pattern,
|
||||||
SmallVectorImpl<MachineInstr *> &InsInstrs,
|
SmallVectorImpl<MachineInstr *> &InsInstrs,
|
||||||
SmallVectorImpl<MachineInstr *> &DelInstrs,
|
SmallVectorImpl<MachineInstr *> &DelInstrs,
|
||||||
DenseMap<unsigned, unsigned> &InstrIdxForVirtReg) const {
|
DenseMap<unsigned, unsigned> &InstrIdxForVirtReg) const;
|
||||||
|
|
||||||
|
/// Attempt to reassociate \P Root and \P Prev according to \P Pattern to
|
||||||
|
/// reduce critical path length.
|
||||||
|
void reassociateOps(MachineInstr &Root, MachineInstr &Prev,
|
||||||
|
MachineCombinerPattern::MC_PATTERN Pattern,
|
||||||
|
SmallVectorImpl<MachineInstr *> &InsInstrs,
|
||||||
|
SmallVectorImpl<MachineInstr *> &DelInstrs,
|
||||||
|
DenseMap<unsigned, unsigned> &InstrIdxForVirtReg) const;
|
||||||
|
|
||||||
|
/// This is an architecture-specific helper function of reassociateOps.
|
||||||
|
/// Set special operand attributes for new instructions after reassociation.
|
||||||
|
virtual void setSpecialOperandAttr(MachineInstr &OldMI1, MachineInstr &OldMI2,
|
||||||
|
MachineInstr &NewMI1,
|
||||||
|
MachineInstr &NewMI2) const {
|
||||||
return;
|
return;
|
||||||
}
|
};
|
||||||
|
|
||||||
/// Return true when a target supports MachineCombiner.
|
/// Return true when a target supports MachineCombiner.
|
||||||
virtual bool useMachineCombiner() const { return false; }
|
virtual bool useMachineCombiner() const { return false; }
|
||||||
|
@ -511,6 +511,216 @@ MachineInstr *TargetInstrInfo::foldMemoryOperand(MachineBasicBlock::iterator MI,
|
|||||||
return --Pos;
|
return --Pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TargetInstrInfo::hasReassociableOperands(
|
||||||
|
const MachineInstr &Inst, const MachineBasicBlock *MBB) const {
|
||||||
|
const MachineOperand &Op1 = Inst.getOperand(1);
|
||||||
|
const MachineOperand &Op2 = Inst.getOperand(2);
|
||||||
|
const MachineRegisterInfo &MRI = MBB->getParent()->getRegInfo();
|
||||||
|
|
||||||
|
// We need virtual register definitions for the operands that we will
|
||||||
|
// reassociate.
|
||||||
|
MachineInstr *MI1 = nullptr;
|
||||||
|
MachineInstr *MI2 = nullptr;
|
||||||
|
if (Op1.isReg() && TargetRegisterInfo::isVirtualRegister(Op1.getReg()))
|
||||||
|
MI1 = MRI.getUniqueVRegDef(Op1.getReg());
|
||||||
|
if (Op2.isReg() && TargetRegisterInfo::isVirtualRegister(Op2.getReg()))
|
||||||
|
MI2 = MRI.getUniqueVRegDef(Op2.getReg());
|
||||||
|
|
||||||
|
// And they need to be in the trace (otherwise, they won't have a depth).
|
||||||
|
if (MI1 && MI2 && MI1->getParent() == MBB && MI2->getParent() == MBB)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TargetInstrInfo::hasReassociableSibling(const MachineInstr &Inst,
|
||||||
|
bool &Commuted) const {
|
||||||
|
const MachineBasicBlock *MBB = Inst.getParent();
|
||||||
|
const MachineRegisterInfo &MRI = MBB->getParent()->getRegInfo();
|
||||||
|
MachineInstr *MI1 = MRI.getUniqueVRegDef(Inst.getOperand(1).getReg());
|
||||||
|
MachineInstr *MI2 = MRI.getUniqueVRegDef(Inst.getOperand(2).getReg());
|
||||||
|
unsigned AssocOpcode = Inst.getOpcode();
|
||||||
|
|
||||||
|
// If only one operand has the same opcode and it's the second source operand,
|
||||||
|
// the operands must be commuted.
|
||||||
|
Commuted = MI1->getOpcode() != AssocOpcode && MI2->getOpcode() == AssocOpcode;
|
||||||
|
if (Commuted)
|
||||||
|
std::swap(MI1, MI2);
|
||||||
|
|
||||||
|
// 1. The previous instruction must be the same type as Inst.
|
||||||
|
// 2. The previous instruction must have virtual register definitions for its
|
||||||
|
// operands in the same basic block as Inst.
|
||||||
|
// 3. The previous instruction's result must only be used by Inst.
|
||||||
|
if (MI1->getOpcode() == AssocOpcode && hasReassociableOperands(*MI1, MBB) &&
|
||||||
|
MRI.hasOneNonDBGUse(MI1->getOperand(0).getReg()))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. The operation must be associative and commutative.
|
||||||
|
// 2. The instruction must have virtual register definitions for its
|
||||||
|
// operands in the same basic block.
|
||||||
|
// 3. The instruction must have a reassociable sibling.
|
||||||
|
bool TargetInstrInfo::isReassociationCandidate(const MachineInstr &Inst,
|
||||||
|
bool &Commuted) const {
|
||||||
|
if (isAssociativeAndCommutative(Inst) &&
|
||||||
|
hasReassociableOperands(Inst, Inst.getParent()) &&
|
||||||
|
hasReassociableSibling(Inst, Commuted))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The concept of the reassociation pass is that these operations can benefit
|
||||||
|
// from this kind of transformation:
|
||||||
|
//
|
||||||
|
// A = ? op ?
|
||||||
|
// B = A op X (Prev)
|
||||||
|
// C = B op Y (Root)
|
||||||
|
// -->
|
||||||
|
// A = ? op ?
|
||||||
|
// B = X op Y
|
||||||
|
// C = A op B
|
||||||
|
//
|
||||||
|
// breaking the dependency between A and B, allowing them to be executed in
|
||||||
|
// parallel (or back-to-back in a pipeline) instead of depending on each other.
|
||||||
|
|
||||||
|
// FIXME: This has the potential to be expensive (compile time) while not
|
||||||
|
// improving the code at all. Some ways to limit the overhead:
|
||||||
|
// 1. Track successful transforms; bail out if hit rate gets too low.
|
||||||
|
// 2. Only enable at -O3 or some other non-default optimization level.
|
||||||
|
// 3. Pre-screen pattern candidates here: if an operand of the previous
|
||||||
|
// instruction is known to not increase the critical path, then don't match
|
||||||
|
// that pattern.
|
||||||
|
bool TargetInstrInfo::getMachineCombinerPatterns(
|
||||||
|
MachineInstr &Root,
|
||||||
|
SmallVectorImpl<MachineCombinerPattern::MC_PATTERN> &Patterns) const {
|
||||||
|
|
||||||
|
bool Commute;
|
||||||
|
if (isReassociationCandidate(Root, Commute)) {
|
||||||
|
// We found a sequence of instructions that may be suitable for a
|
||||||
|
// reassociation of operands to increase ILP. Specify each commutation
|
||||||
|
// possibility for the Prev instruction in the sequence and let the
|
||||||
|
// machine combiner decide if changing the operands is worthwhile.
|
||||||
|
if (Commute) {
|
||||||
|
Patterns.push_back(MachineCombinerPattern::MC_REASSOC_AX_YB);
|
||||||
|
Patterns.push_back(MachineCombinerPattern::MC_REASSOC_XA_YB);
|
||||||
|
} else {
|
||||||
|
Patterns.push_back(MachineCombinerPattern::MC_REASSOC_AX_BY);
|
||||||
|
Patterns.push_back(MachineCombinerPattern::MC_REASSOC_XA_BY);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Attempt the reassociation transformation to reduce critical path length.
|
||||||
|
/// See the above comments before getMachineCombinerPatterns().
|
||||||
|
void TargetInstrInfo::reassociateOps(
|
||||||
|
MachineInstr &Root, MachineInstr &Prev,
|
||||||
|
MachineCombinerPattern::MC_PATTERN Pattern,
|
||||||
|
SmallVectorImpl<MachineInstr *> &InsInstrs,
|
||||||
|
SmallVectorImpl<MachineInstr *> &DelInstrs,
|
||||||
|
DenseMap<unsigned, unsigned> &InstrIdxForVirtReg) const {
|
||||||
|
MachineFunction *MF = Root.getParent()->getParent();
|
||||||
|
MachineRegisterInfo &MRI = MF->getRegInfo();
|
||||||
|
const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo();
|
||||||
|
const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();
|
||||||
|
const TargetRegisterClass *RC = Root.getRegClassConstraint(0, TII, TRI);
|
||||||
|
|
||||||
|
// This array encodes the operand index for each parameter because the
|
||||||
|
// operands may be commuted. Each row corresponds to a pattern value,
|
||||||
|
// and each column specifies the index of A, B, X, Y.
|
||||||
|
unsigned OpIdx[4][4] = {
|
||||||
|
{ 1, 1, 2, 2 },
|
||||||
|
{ 1, 2, 2, 1 },
|
||||||
|
{ 2, 1, 1, 2 },
|
||||||
|
{ 2, 2, 1, 1 }
|
||||||
|
};
|
||||||
|
|
||||||
|
MachineOperand &OpA = Prev.getOperand(OpIdx[Pattern][0]);
|
||||||
|
MachineOperand &OpB = Root.getOperand(OpIdx[Pattern][1]);
|
||||||
|
MachineOperand &OpX = Prev.getOperand(OpIdx[Pattern][2]);
|
||||||
|
MachineOperand &OpY = Root.getOperand(OpIdx[Pattern][3]);
|
||||||
|
MachineOperand &OpC = Root.getOperand(0);
|
||||||
|
|
||||||
|
unsigned RegA = OpA.getReg();
|
||||||
|
unsigned RegB = OpB.getReg();
|
||||||
|
unsigned RegX = OpX.getReg();
|
||||||
|
unsigned RegY = OpY.getReg();
|
||||||
|
unsigned RegC = OpC.getReg();
|
||||||
|
|
||||||
|
if (TargetRegisterInfo::isVirtualRegister(RegA))
|
||||||
|
MRI.constrainRegClass(RegA, RC);
|
||||||
|
if (TargetRegisterInfo::isVirtualRegister(RegB))
|
||||||
|
MRI.constrainRegClass(RegB, RC);
|
||||||
|
if (TargetRegisterInfo::isVirtualRegister(RegX))
|
||||||
|
MRI.constrainRegClass(RegX, RC);
|
||||||
|
if (TargetRegisterInfo::isVirtualRegister(RegY))
|
||||||
|
MRI.constrainRegClass(RegY, RC);
|
||||||
|
if (TargetRegisterInfo::isVirtualRegister(RegC))
|
||||||
|
MRI.constrainRegClass(RegC, RC);
|
||||||
|
|
||||||
|
// Create a new virtual register for the result of (X op Y) instead of
|
||||||
|
// recycling RegB because the MachineCombiner's computation of the critical
|
||||||
|
// path requires a new register definition rather than an existing one.
|
||||||
|
unsigned NewVR = MRI.createVirtualRegister(RC);
|
||||||
|
InstrIdxForVirtReg.insert(std::make_pair(NewVR, 0));
|
||||||
|
|
||||||
|
unsigned Opcode = Root.getOpcode();
|
||||||
|
bool KillA = OpA.isKill();
|
||||||
|
bool KillX = OpX.isKill();
|
||||||
|
bool KillY = OpY.isKill();
|
||||||
|
|
||||||
|
// Create new instructions for insertion.
|
||||||
|
MachineInstrBuilder MIB1 =
|
||||||
|
BuildMI(*MF, Prev.getDebugLoc(), TII->get(Opcode), NewVR)
|
||||||
|
.addReg(RegX, getKillRegState(KillX))
|
||||||
|
.addReg(RegY, getKillRegState(KillY));
|
||||||
|
MachineInstrBuilder MIB2 =
|
||||||
|
BuildMI(*MF, Root.getDebugLoc(), TII->get(Opcode), RegC)
|
||||||
|
.addReg(RegA, getKillRegState(KillA))
|
||||||
|
.addReg(NewVR, getKillRegState(true));
|
||||||
|
|
||||||
|
setSpecialOperandAttr(Root, Prev, *MIB1, *MIB2);
|
||||||
|
|
||||||
|
// Record new instructions for insertion and old instructions for deletion.
|
||||||
|
InsInstrs.push_back(MIB1);
|
||||||
|
InsInstrs.push_back(MIB2);
|
||||||
|
DelInstrs.push_back(&Prev);
|
||||||
|
DelInstrs.push_back(&Root);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TargetInstrInfo::genAlternativeCodeSequence(
|
||||||
|
MachineInstr &Root, MachineCombinerPattern::MC_PATTERN Pattern,
|
||||||
|
SmallVectorImpl<MachineInstr *> &InsInstrs,
|
||||||
|
SmallVectorImpl<MachineInstr *> &DelInstrs,
|
||||||
|
DenseMap<unsigned, unsigned> &InstIdxForVirtReg) const {
|
||||||
|
MachineRegisterInfo &MRI = Root.getParent()->getParent()->getRegInfo();
|
||||||
|
|
||||||
|
// Select the previous instruction in the sequence based on the input pattern.
|
||||||
|
MachineInstr *Prev = nullptr;
|
||||||
|
switch (Pattern) {
|
||||||
|
case MachineCombinerPattern::MC_REASSOC_AX_BY:
|
||||||
|
case MachineCombinerPattern::MC_REASSOC_XA_BY:
|
||||||
|
Prev = MRI.getUniqueVRegDef(Root.getOperand(1).getReg());
|
||||||
|
break;
|
||||||
|
case MachineCombinerPattern::MC_REASSOC_AX_YB:
|
||||||
|
case MachineCombinerPattern::MC_REASSOC_XA_YB:
|
||||||
|
Prev = MRI.getUniqueVRegDef(Root.getOperand(2).getReg());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(Prev && "Unknown pattern for machine combiner");
|
||||||
|
|
||||||
|
reassociateOps(Root, *Prev, Pattern, InsInstrs, DelInstrs, InstIdxForVirtReg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/// foldMemoryOperand - Same as the previous version except it allows folding
|
/// foldMemoryOperand - Same as the previous version except it allows folding
|
||||||
/// of any load and store from / to any address, not just from a specific
|
/// of any load and store from / to any address, not just from a specific
|
||||||
/// stack slot.
|
/// stack slot.
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "AArch64InstrInfo.h"
|
#include "AArch64InstrInfo.h"
|
||||||
#include "AArch64MachineCombinerPattern.h"
|
|
||||||
#include "AArch64Subtarget.h"
|
#include "AArch64Subtarget.h"
|
||||||
#include "MCTargetDesc/AArch64AddressingModes.h"
|
#include "MCTargetDesc/AArch64AddressingModes.h"
|
||||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
//===- AArch64MachineCombinerPattern.h -===//
|
|
||||||
//===- AArch64 instruction pattern supported by combiner -===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file is distributed under the University of Illinois Open Source
|
|
||||||
// License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This file defines instruction pattern supported by combiner
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#ifndef LLVM_LIB_TARGET_AARCH64_AARCH64MACHINECOMBINERPATTERN_H
|
|
||||||
#define LLVM_LIB_TARGET_AARCH64_AARCH64MACHINECOMBINERPATTERN_H
|
|
||||||
|
|
||||||
namespace llvm {
|
|
||||||
|
|
||||||
/// Enumeration of instruction pattern supported by machine combiner
|
|
||||||
///
|
|
||||||
///
|
|
||||||
namespace MachineCombinerPattern {
|
|
||||||
enum MC_PATTERN : int {
|
|
||||||
MC_NONE = 0,
|
|
||||||
MC_MULADDW_OP1 = 1,
|
|
||||||
MC_MULADDW_OP2 = 2,
|
|
||||||
MC_MULSUBW_OP1 = 3,
|
|
||||||
MC_MULSUBW_OP2 = 4,
|
|
||||||
MC_MULADDWI_OP1 = 5,
|
|
||||||
MC_MULSUBWI_OP1 = 6,
|
|
||||||
MC_MULADDX_OP1 = 7,
|
|
||||||
MC_MULADDX_OP2 = 8,
|
|
||||||
MC_MULSUBX_OP1 = 9,
|
|
||||||
MC_MULSUBX_OP2 = 10,
|
|
||||||
MC_MULADDXI_OP1 = 11,
|
|
||||||
MC_MULSUBXI_OP1 = 12
|
|
||||||
};
|
|
||||||
} // end namespace MachineCombinerPattern
|
|
||||||
} // end namespace llvm
|
|
||||||
|
|
||||||
#endif
|
|
@ -189,73 +189,13 @@ int PPCInstrInfo::getOperandLatency(const InstrItineraryData *ItinData,
|
|||||||
return Latency;
|
return Latency;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool hasVirtualRegDefsInBasicBlock(const MachineInstr &Inst,
|
|
||||||
const MachineBasicBlock *MBB) {
|
|
||||||
const MachineOperand &Op1 = Inst.getOperand(1);
|
|
||||||
const MachineOperand &Op2 = Inst.getOperand(2);
|
|
||||||
const MachineRegisterInfo &MRI = MBB->getParent()->getRegInfo();
|
|
||||||
|
|
||||||
// We need virtual register definitions.
|
|
||||||
MachineInstr *MI1 = nullptr;
|
|
||||||
MachineInstr *MI2 = nullptr;
|
|
||||||
if (Op1.isReg() && TargetRegisterInfo::isVirtualRegister(Op1.getReg()))
|
|
||||||
MI1 = MRI.getUniqueVRegDef(Op1.getReg());
|
|
||||||
if (Op2.isReg() && TargetRegisterInfo::isVirtualRegister(Op2.getReg()))
|
|
||||||
MI2 = MRI.getUniqueVRegDef(Op2.getReg());
|
|
||||||
|
|
||||||
// And they need to be in the trace (otherwise, they won't have a depth).
|
|
||||||
if (MI1 && MI2 && MI1->getParent() == MBB && MI2->getParent() == MBB)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool hasReassocSibling(const MachineInstr &Inst, bool &Commuted) {
|
|
||||||
const MachineBasicBlock *MBB = Inst.getParent();
|
|
||||||
const MachineRegisterInfo &MRI = MBB->getParent()->getRegInfo();
|
|
||||||
MachineInstr *MI1 = MRI.getUniqueVRegDef(Inst.getOperand(1).getReg());
|
|
||||||
MachineInstr *MI2 = MRI.getUniqueVRegDef(Inst.getOperand(2).getReg());
|
|
||||||
unsigned AssocOpcode = Inst.getOpcode();
|
|
||||||
|
|
||||||
// If only one operand has the same opcode and it's the second source operand,
|
|
||||||
// the operands must be commuted.
|
|
||||||
Commuted = MI1->getOpcode() != AssocOpcode && MI2->getOpcode() == AssocOpcode;
|
|
||||||
if (Commuted)
|
|
||||||
std::swap(MI1, MI2);
|
|
||||||
|
|
||||||
// 1. The previous instruction must be the same type as Inst.
|
|
||||||
// 2. The previous instruction must have virtual register definitions for its
|
|
||||||
// operands in the same basic block as Inst.
|
|
||||||
// 3. The previous instruction's result must only be used by Inst.
|
|
||||||
if (MI1->getOpcode() == AssocOpcode &&
|
|
||||||
hasVirtualRegDefsInBasicBlock(*MI1, MBB) &&
|
|
||||||
MRI.hasOneNonDBGUse(MI1->getOperand(0).getReg()))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This function does not list all associative and commutative operations, but
|
// This function does not list all associative and commutative operations, but
|
||||||
// only those worth feeding through the machine combiner in an attempt to
|
// only those worth feeding through the machine combiner in an attempt to
|
||||||
// reduce the critical path. Mostly, this means floating-point operations,
|
// reduce the critical path. Mostly, this means floating-point operations,
|
||||||
// because they have high latencies (compared to other operations, such and
|
// because they have high latencies (compared to other operations, such and
|
||||||
// and/or, which are also associative and commutative, but have low latencies).
|
// and/or, which are also associative and commutative, but have low latencies).
|
||||||
//
|
bool PPCInstrInfo::isAssociativeAndCommutative(const MachineInstr &Inst) const {
|
||||||
// The concept is that these operations can benefit from this kind of
|
switch (Inst.getOpcode()) {
|
||||||
// transformation:
|
|
||||||
//
|
|
||||||
// A = ? op ?
|
|
||||||
// B = A op X
|
|
||||||
// C = B op Y
|
|
||||||
// -->
|
|
||||||
// A = ? op ?
|
|
||||||
// B = X op Y
|
|
||||||
// C = A op B
|
|
||||||
//
|
|
||||||
// breaking the dependency between A and B, allowing them to be executed in
|
|
||||||
// parallel (or back-to-back in a pipeline) instead of depending on each other.
|
|
||||||
static bool isAssociativeAndCommutative(unsigned Opcode) {
|
|
||||||
switch (Opcode) {
|
|
||||||
// FP Add:
|
// FP Add:
|
||||||
case PPC::FADD:
|
case PPC::FADD:
|
||||||
case PPC::FADDS:
|
case PPC::FADDS:
|
||||||
@ -288,26 +228,9 @@ static bool isAssociativeAndCommutative(unsigned Opcode) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return true if the input instruction is part of a chain of dependent ops
|
bool PPCInstrInfo::getMachineCombinerPatterns(
|
||||||
/// that are suitable for reassociation, otherwise return false.
|
MachineInstr &Root,
|
||||||
/// If the instruction's operands must be commuted to have a previous
|
SmallVectorImpl<MachineCombinerPattern::MC_PATTERN> &Patterns) const {
|
||||||
/// instruction of the same type define the first source operand, Commuted will
|
|
||||||
/// be set to true.
|
|
||||||
static bool isReassocCandidate(const MachineInstr &Inst, bool &Commuted) {
|
|
||||||
// 1. The operation must be associative and commutative.
|
|
||||||
// 2. The instruction must have virtual register definitions for its
|
|
||||||
// operands in the same basic block.
|
|
||||||
// 3. The instruction must have a reassociable sibling.
|
|
||||||
if (isAssociativeAndCommutative(Inst.getOpcode()) &&
|
|
||||||
hasVirtualRegDefsInBasicBlock(Inst, Inst.getParent()) &&
|
|
||||||
hasReassocSibling(Inst, Commuted))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PPCInstrInfo::getMachineCombinerPatterns(MachineInstr &Root,
|
|
||||||
SmallVectorImpl<MachineCombinerPattern::MC_PATTERN> &Patterns) const {
|
|
||||||
// Using the machine combiner in this way is potentially expensive, so
|
// Using the machine combiner in this way is potentially expensive, so
|
||||||
// restrict to when aggressive optimizations are desired.
|
// restrict to when aggressive optimizations are desired.
|
||||||
if (Subtarget.getTargetMachine().getOptLevel() != CodeGenOpt::Aggressive)
|
if (Subtarget.getTargetMachine().getOptLevel() != CodeGenOpt::Aggressive)
|
||||||
@ -317,135 +240,7 @@ bool PPCInstrInfo::getMachineCombinerPatterns(MachineInstr &Root,
|
|||||||
if (!Root.getParent()->getParent()->getTarget().Options.UnsafeFPMath)
|
if (!Root.getParent()->getParent()->getTarget().Options.UnsafeFPMath)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Look for this reassociation pattern:
|
return TargetInstrInfo::getMachineCombinerPatterns(Root, Patterns);
|
||||||
// B = A op X (Prev)
|
|
||||||
// C = B op Y (Root)
|
|
||||||
|
|
||||||
// FIXME: We should also match FMA operations here, where we consider the
|
|
||||||
// 'part' of the FMA, either the addition or the multiplication, paired with
|
|
||||||
// an actual addition or multiplication.
|
|
||||||
|
|
||||||
bool Commute;
|
|
||||||
if (isReassocCandidate(Root, Commute)) {
|
|
||||||
// We found a sequence of instructions that may be suitable for a
|
|
||||||
// reassociation of operands to increase ILP. Specify each commutation
|
|
||||||
// possibility for the Prev instruction in the sequence and let the
|
|
||||||
// machine combiner decide if changing the operands is worthwhile.
|
|
||||||
if (Commute) {
|
|
||||||
Patterns.push_back(MachineCombinerPattern::MC_REASSOC_AX_YB);
|
|
||||||
Patterns.push_back(MachineCombinerPattern::MC_REASSOC_XA_YB);
|
|
||||||
} else {
|
|
||||||
Patterns.push_back(MachineCombinerPattern::MC_REASSOC_AX_BY);
|
|
||||||
Patterns.push_back(MachineCombinerPattern::MC_REASSOC_XA_BY);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Attempt the following reassociation to reduce critical path length:
|
|
||||||
/// B = A op X (Prev)
|
|
||||||
/// C = B op Y (Root)
|
|
||||||
/// ===>
|
|
||||||
/// B = X op Y
|
|
||||||
/// C = A op B
|
|
||||||
static void reassociateOps(MachineInstr &Root, MachineInstr &Prev,
|
|
||||||
MachineCombinerPattern::MC_PATTERN Pattern,
|
|
||||||
SmallVectorImpl<MachineInstr *> &InsInstrs,
|
|
||||||
SmallVectorImpl<MachineInstr *> &DelInstrs,
|
|
||||||
DenseMap<unsigned, unsigned> &InstrIdxForVirtReg) {
|
|
||||||
MachineFunction *MF = Root.getParent()->getParent();
|
|
||||||
MachineRegisterInfo &MRI = MF->getRegInfo();
|
|
||||||
const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo();
|
|
||||||
const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();
|
|
||||||
const TargetRegisterClass *RC = Root.getRegClassConstraint(0, TII, TRI);
|
|
||||||
|
|
||||||
// This array encodes the operand index for each parameter because the
|
|
||||||
// operands may be commuted. Each row corresponds to a pattern value,
|
|
||||||
// and each column specifies the index of A, B, X, Y.
|
|
||||||
unsigned OpIdx[4][4] = {
|
|
||||||
{ 1, 1, 2, 2 },
|
|
||||||
{ 1, 2, 2, 1 },
|
|
||||||
{ 2, 1, 1, 2 },
|
|
||||||
{ 2, 2, 1, 1 }
|
|
||||||
};
|
|
||||||
|
|
||||||
MachineOperand &OpA = Prev.getOperand(OpIdx[Pattern][0]);
|
|
||||||
MachineOperand &OpB = Root.getOperand(OpIdx[Pattern][1]);
|
|
||||||
MachineOperand &OpX = Prev.getOperand(OpIdx[Pattern][2]);
|
|
||||||
MachineOperand &OpY = Root.getOperand(OpIdx[Pattern][3]);
|
|
||||||
MachineOperand &OpC = Root.getOperand(0);
|
|
||||||
|
|
||||||
unsigned RegA = OpA.getReg();
|
|
||||||
unsigned RegB = OpB.getReg();
|
|
||||||
unsigned RegX = OpX.getReg();
|
|
||||||
unsigned RegY = OpY.getReg();
|
|
||||||
unsigned RegC = OpC.getReg();
|
|
||||||
|
|
||||||
if (TargetRegisterInfo::isVirtualRegister(RegA))
|
|
||||||
MRI.constrainRegClass(RegA, RC);
|
|
||||||
if (TargetRegisterInfo::isVirtualRegister(RegB))
|
|
||||||
MRI.constrainRegClass(RegB, RC);
|
|
||||||
if (TargetRegisterInfo::isVirtualRegister(RegX))
|
|
||||||
MRI.constrainRegClass(RegX, RC);
|
|
||||||
if (TargetRegisterInfo::isVirtualRegister(RegY))
|
|
||||||
MRI.constrainRegClass(RegY, RC);
|
|
||||||
if (TargetRegisterInfo::isVirtualRegister(RegC))
|
|
||||||
MRI.constrainRegClass(RegC, RC);
|
|
||||||
|
|
||||||
// Create a new virtual register for the result of (X op Y) instead of
|
|
||||||
// recycling RegB because the MachineCombiner's computation of the critical
|
|
||||||
// path requires a new register definition rather than an existing one.
|
|
||||||
unsigned NewVR = MRI.createVirtualRegister(RC);
|
|
||||||
InstrIdxForVirtReg.insert(std::make_pair(NewVR, 0));
|
|
||||||
|
|
||||||
unsigned Opcode = Root.getOpcode();
|
|
||||||
bool KillA = OpA.isKill();
|
|
||||||
bool KillX = OpX.isKill();
|
|
||||||
bool KillY = OpY.isKill();
|
|
||||||
|
|
||||||
// Create new instructions for insertion.
|
|
||||||
MachineInstrBuilder MIB1 =
|
|
||||||
BuildMI(*MF, Prev.getDebugLoc(), TII->get(Opcode), NewVR)
|
|
||||||
.addReg(RegX, getKillRegState(KillX))
|
|
||||||
.addReg(RegY, getKillRegState(KillY));
|
|
||||||
InsInstrs.push_back(MIB1);
|
|
||||||
|
|
||||||
MachineInstrBuilder MIB2 =
|
|
||||||
BuildMI(*MF, Root.getDebugLoc(), TII->get(Opcode), RegC)
|
|
||||||
.addReg(RegA, getKillRegState(KillA))
|
|
||||||
.addReg(NewVR, getKillRegState(true));
|
|
||||||
InsInstrs.push_back(MIB2);
|
|
||||||
|
|
||||||
// Record old instructions for deletion.
|
|
||||||
DelInstrs.push_back(&Prev);
|
|
||||||
DelInstrs.push_back(&Root);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PPCInstrInfo::genAlternativeCodeSequence(
|
|
||||||
MachineInstr &Root,
|
|
||||||
MachineCombinerPattern::MC_PATTERN Pattern,
|
|
||||||
SmallVectorImpl<MachineInstr *> &InsInstrs,
|
|
||||||
SmallVectorImpl<MachineInstr *> &DelInstrs,
|
|
||||||
DenseMap<unsigned, unsigned> &InstIdxForVirtReg) const {
|
|
||||||
MachineRegisterInfo &MRI = Root.getParent()->getParent()->getRegInfo();
|
|
||||||
|
|
||||||
// Select the previous instruction in the sequence based on the input pattern.
|
|
||||||
MachineInstr *Prev = nullptr;
|
|
||||||
switch (Pattern) {
|
|
||||||
case MachineCombinerPattern::MC_REASSOC_AX_BY:
|
|
||||||
case MachineCombinerPattern::MC_REASSOC_XA_BY:
|
|
||||||
Prev = MRI.getUniqueVRegDef(Root.getOperand(1).getReg());
|
|
||||||
break;
|
|
||||||
case MachineCombinerPattern::MC_REASSOC_AX_YB:
|
|
||||||
case MachineCombinerPattern::MC_REASSOC_XA_YB:
|
|
||||||
Prev = MRI.getUniqueVRegDef(Root.getOperand(2).getReg());
|
|
||||||
}
|
|
||||||
assert(Prev && "Unknown pattern for machine combiner");
|
|
||||||
|
|
||||||
reassociateOps(Root, *Prev, Pattern, InsInstrs, DelInstrs, InstIdxForVirtReg);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detect 32 -> 64-bit extensions where we may reuse the low sub-register.
|
// Detect 32 -> 64-bit extensions where we may reuse the low sub-register.
|
||||||
|
@ -63,19 +63,6 @@ enum PPC970_Unit {
|
|||||||
};
|
};
|
||||||
} // end namespace PPCII
|
} // end namespace PPCII
|
||||||
|
|
||||||
namespace MachineCombinerPattern {
|
|
||||||
enum MC_PATTERN : int {
|
|
||||||
// These are commutative variants for reassociating a computation chain
|
|
||||||
// of the form:
|
|
||||||
// B = A op X (Prev)
|
|
||||||
// C = B op Y (Root)
|
|
||||||
MC_REASSOC_AX_BY = 0,
|
|
||||||
MC_REASSOC_AX_YB = 1,
|
|
||||||
MC_REASSOC_XA_BY = 2,
|
|
||||||
MC_REASSOC_XA_YB = 3,
|
|
||||||
};
|
|
||||||
} // end namespace MachineCombinerPattern
|
|
||||||
|
|
||||||
class PPCSubtarget;
|
class PPCSubtarget;
|
||||||
class PPCInstrInfo : public PPCGenInstrInfo {
|
class PPCInstrInfo : public PPCGenInstrInfo {
|
||||||
PPCSubtarget &Subtarget;
|
PPCSubtarget &Subtarget;
|
||||||
@ -135,21 +122,15 @@ public:
|
|||||||
bool useMachineCombiner() const override {
|
bool useMachineCombiner() const override {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return true when there is potentially a faster code sequence
|
/// Return true when there is potentially a faster code sequence
|
||||||
/// for an instruction chain ending in <Root>. All potential patterns are
|
/// for an instruction chain ending in <Root>. All potential patterns are
|
||||||
/// output in the <Pattern> array.
|
/// output in the <Pattern> array.
|
||||||
bool getMachineCombinerPatterns(
|
bool getMachineCombinerPatterns(
|
||||||
MachineInstr &Root,
|
MachineInstr &Root,
|
||||||
SmallVectorImpl<MachineCombinerPattern::MC_PATTERN> &P) const override;
|
SmallVectorImpl<MachineCombinerPattern::MC_PATTERN> &P) const override;
|
||||||
|
|
||||||
/// When getMachineCombinerPatterns() finds a pattern, this function generates
|
bool isAssociativeAndCommutative(const MachineInstr &Inst) const override;
|
||||||
/// the instructions that could replace the original code sequence.
|
|
||||||
void genAlternativeCodeSequence(
|
|
||||||
MachineInstr &Root, MachineCombinerPattern::MC_PATTERN P,
|
|
||||||
SmallVectorImpl<MachineInstr *> &InsInstrs,
|
|
||||||
SmallVectorImpl<MachineInstr *> &DelInstrs,
|
|
||||||
DenseMap<unsigned, unsigned> &InstrIdxForVirtReg) const override;
|
|
||||||
|
|
||||||
bool isCoalescableExtInstr(const MachineInstr &MI,
|
bool isCoalescableExtInstr(const MachineInstr &MI,
|
||||||
unsigned &SrcReg, unsigned &DstReg,
|
unsigned &SrcReg, unsigned &DstReg,
|
||||||
|
@ -6328,13 +6328,10 @@ hasHighOperandLatency(const TargetSchedModel &SchedModel,
|
|||||||
return isHighLatencyDef(DefMI->getOpcode());
|
return isHighLatencyDef(DefMI->getOpcode());
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool hasReassociableOperands(const MachineInstr &Inst,
|
bool X86InstrInfo::hasReassociableOperands(const MachineInstr &Inst,
|
||||||
const MachineBasicBlock *MBB) {
|
const MachineBasicBlock *MBB) const {
|
||||||
assert((Inst.getNumOperands() == 3 || Inst.getNumOperands() == 4) &&
|
assert((Inst.getNumOperands() == 3 || Inst.getNumOperands() == 4) &&
|
||||||
"Reassociation needs binary operators");
|
"Reassociation needs binary operators");
|
||||||
const MachineOperand &Op1 = Inst.getOperand(1);
|
|
||||||
const MachineOperand &Op2 = Inst.getOperand(2);
|
|
||||||
const MachineRegisterInfo &MRI = MBB->getParent()->getRegInfo();
|
|
||||||
|
|
||||||
// Integer binary math/logic instructions have a third source operand:
|
// Integer binary math/logic instructions have a third source operand:
|
||||||
// the EFLAGS register. That operand must be both defined here and never
|
// the EFLAGS register. That operand must be both defined here and never
|
||||||
@ -6349,53 +6346,15 @@ static bool hasReassociableOperands(const MachineInstr &Inst,
|
|||||||
if (!Inst.getOperand(3).isDead())
|
if (!Inst.getOperand(3).isDead())
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need virtual register definitions for the operands that we will
|
|
||||||
// reassociate.
|
|
||||||
MachineInstr *MI1 = nullptr;
|
|
||||||
MachineInstr *MI2 = nullptr;
|
|
||||||
if (Op1.isReg() && TargetRegisterInfo::isVirtualRegister(Op1.getReg()))
|
|
||||||
MI1 = MRI.getUniqueVRegDef(Op1.getReg());
|
|
||||||
if (Op2.isReg() && TargetRegisterInfo::isVirtualRegister(Op2.getReg()))
|
|
||||||
MI2 = MRI.getUniqueVRegDef(Op2.getReg());
|
|
||||||
|
|
||||||
// And they need to be in the trace (otherwise, they won't have a depth).
|
return TargetInstrInfo::hasReassociableOperands(Inst, MBB);
|
||||||
if (MI1 && MI2 && MI1->getParent() == MBB && MI2->getParent() == MBB)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool hasReassociableSibling(const MachineInstr &Inst, bool &Commuted) {
|
|
||||||
const MachineBasicBlock *MBB = Inst.getParent();
|
|
||||||
const MachineRegisterInfo &MRI = MBB->getParent()->getRegInfo();
|
|
||||||
MachineInstr *MI1 = MRI.getUniqueVRegDef(Inst.getOperand(1).getReg());
|
|
||||||
MachineInstr *MI2 = MRI.getUniqueVRegDef(Inst.getOperand(2).getReg());
|
|
||||||
unsigned AssocOpcode = Inst.getOpcode();
|
|
||||||
|
|
||||||
// If only one operand has the same opcode and it's the second source operand,
|
|
||||||
// the operands must be commuted.
|
|
||||||
Commuted = MI1->getOpcode() != AssocOpcode && MI2->getOpcode() == AssocOpcode;
|
|
||||||
if (Commuted)
|
|
||||||
std::swap(MI1, MI2);
|
|
||||||
|
|
||||||
// 1. The previous instruction must be the same type as Inst.
|
|
||||||
// 2. The previous instruction must have virtual register definitions for its
|
|
||||||
// operands in the same basic block as Inst.
|
|
||||||
// 3. The previous instruction's result must only be used by Inst.
|
|
||||||
if (MI1->getOpcode() == AssocOpcode &&
|
|
||||||
hasReassociableOperands(*MI1, MBB) &&
|
|
||||||
MRI.hasOneNonDBGUse(MI1->getOperand(0).getReg()))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: There are many more machine instruction opcodes to match:
|
// TODO: There are many more machine instruction opcodes to match:
|
||||||
// 1. Other data types (integer, vectors)
|
// 1. Other data types (integer, vectors)
|
||||||
// 2. Other math / logic operations (xor, or)
|
// 2. Other math / logic operations (xor, or)
|
||||||
// 3. Other forms of the same operation (intrinsics and other variants)
|
// 3. Other forms of the same operation (intrinsics and other variants)
|
||||||
static bool isAssociativeAndCommutative(const MachineInstr &Inst) {
|
bool X86InstrInfo::isAssociativeAndCommutative(const MachineInstr &Inst) const {
|
||||||
switch (Inst.getOpcode()) {
|
switch (Inst.getOpcode()) {
|
||||||
case X86::AND8rr:
|
case X86::AND8rr:
|
||||||
case X86::AND16rr:
|
case X86::AND16rr:
|
||||||
@ -6468,63 +6427,12 @@ static bool isAssociativeAndCommutative(const MachineInstr &Inst) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return true if the input instruction is part of a chain of dependent ops
|
|
||||||
/// that are suitable for reassociation, otherwise return false.
|
|
||||||
/// If the instruction's operands must be commuted to have a previous
|
|
||||||
/// instruction of the same type define the first source operand, Commuted will
|
|
||||||
/// be set to true.
|
|
||||||
static bool isReassociationCandidate(const MachineInstr &Inst, bool &Commuted) {
|
|
||||||
// 1. The operation must be associative and commutative.
|
|
||||||
// 2. The instruction must have virtual register definitions for its
|
|
||||||
// operands in the same basic block.
|
|
||||||
// 3. The instruction must have a reassociable sibling.
|
|
||||||
if (isAssociativeAndCommutative(Inst) &&
|
|
||||||
hasReassociableOperands(Inst, Inst.getParent()) &&
|
|
||||||
hasReassociableSibling(Inst, Commuted))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: This has the potential to be expensive (compile time) while not
|
|
||||||
// improving the code at all. Some ways to limit the overhead:
|
|
||||||
// 1. Track successful transforms; bail out if hit rate gets too low.
|
|
||||||
// 2. Only enable at -O3 or some other non-default optimization level.
|
|
||||||
// 3. Pre-screen pattern candidates here: if an operand of the previous
|
|
||||||
// instruction is known to not increase the critical path, then don't match
|
|
||||||
// that pattern.
|
|
||||||
bool X86InstrInfo::getMachineCombinerPatterns(MachineInstr &Root,
|
|
||||||
SmallVectorImpl<MachineCombinerPattern::MC_PATTERN> &Patterns) const {
|
|
||||||
// TODO: There is nothing x86-specific here except the instruction type.
|
|
||||||
// This logic could be hoisted into the machine combiner pass itself.
|
|
||||||
|
|
||||||
// Look for this reassociation pattern:
|
|
||||||
// B = A op X (Prev)
|
|
||||||
// C = B op Y (Root)
|
|
||||||
|
|
||||||
bool Commute;
|
|
||||||
if (isReassociationCandidate(Root, Commute)) {
|
|
||||||
// We found a sequence of instructions that may be suitable for a
|
|
||||||
// reassociation of operands to increase ILP. Specify each commutation
|
|
||||||
// possibility for the Prev instruction in the sequence and let the
|
|
||||||
// machine combiner decide if changing the operands is worthwhile.
|
|
||||||
if (Commute) {
|
|
||||||
Patterns.push_back(MachineCombinerPattern::MC_REASSOC_AX_YB);
|
|
||||||
Patterns.push_back(MachineCombinerPattern::MC_REASSOC_XA_YB);
|
|
||||||
} else {
|
|
||||||
Patterns.push_back(MachineCombinerPattern::MC_REASSOC_AX_BY);
|
|
||||||
Patterns.push_back(MachineCombinerPattern::MC_REASSOC_XA_BY);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This is an architecture-specific helper function of reassociateOps.
|
/// This is an architecture-specific helper function of reassociateOps.
|
||||||
/// Set special operand attributes for new instructions after reassociation.
|
/// Set special operand attributes for new instructions after reassociation.
|
||||||
static void setSpecialOperandAttr(MachineInstr &OldMI1, MachineInstr &OldMI2,
|
void X86InstrInfo::setSpecialOperandAttr(MachineInstr &OldMI1,
|
||||||
MachineInstr &NewMI1, MachineInstr &NewMI2) {
|
MachineInstr &OldMI2,
|
||||||
|
MachineInstr &NewMI1,
|
||||||
|
MachineInstr &NewMI2) const {
|
||||||
// Integer instructions define an implicit EFLAGS source register operand as
|
// Integer instructions define an implicit EFLAGS source register operand as
|
||||||
// the third source (fourth total) operand.
|
// the third source (fourth total) operand.
|
||||||
if (OldMI1.getNumOperands() != 4 || OldMI2.getNumOperands() != 4)
|
if (OldMI1.getNumOperands() != 4 || OldMI2.getNumOperands() != 4)
|
||||||
@ -6532,7 +6440,7 @@ static void setSpecialOperandAttr(MachineInstr &OldMI1, MachineInstr &OldMI2,
|
|||||||
|
|
||||||
assert(NewMI1.getNumOperands() == 4 && NewMI2.getNumOperands() == 4 &&
|
assert(NewMI1.getNumOperands() == 4 && NewMI2.getNumOperands() == 4 &&
|
||||||
"Unexpected instruction type for reassociation");
|
"Unexpected instruction type for reassociation");
|
||||||
|
|
||||||
MachineOperand &OldOp1 = OldMI1.getOperand(3);
|
MachineOperand &OldOp1 = OldMI1.getOperand(3);
|
||||||
MachineOperand &OldOp2 = OldMI2.getOperand(3);
|
MachineOperand &OldOp2 = OldMI2.getOperand(3);
|
||||||
MachineOperand &NewOp1 = NewMI1.getOperand(3);
|
MachineOperand &NewOp1 = NewMI1.getOperand(3);
|
||||||
@ -6559,111 +6467,6 @@ static void setSpecialOperandAttr(MachineInstr &OldMI1, MachineInstr &OldMI2,
|
|||||||
NewOp2.setIsDead();
|
NewOp2.setIsDead();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempt the following reassociation to reduce critical path length:
|
|
||||||
/// B = A op X (Prev)
|
|
||||||
/// C = B op Y (Root)
|
|
||||||
/// ===>
|
|
||||||
/// B = X op Y
|
|
||||||
/// C = A op B
|
|
||||||
static void reassociateOps(MachineInstr &Root, MachineInstr &Prev,
|
|
||||||
MachineCombinerPattern::MC_PATTERN Pattern,
|
|
||||||
SmallVectorImpl<MachineInstr *> &InsInstrs,
|
|
||||||
SmallVectorImpl<MachineInstr *> &DelInstrs,
|
|
||||||
DenseMap<unsigned, unsigned> &InstrIdxForVirtReg) {
|
|
||||||
MachineFunction *MF = Root.getParent()->getParent();
|
|
||||||
MachineRegisterInfo &MRI = MF->getRegInfo();
|
|
||||||
const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo();
|
|
||||||
const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();
|
|
||||||
const TargetRegisterClass *RC = Root.getRegClassConstraint(0, TII, TRI);
|
|
||||||
|
|
||||||
// This array encodes the operand index for each parameter because the
|
|
||||||
// operands may be commuted. Each row corresponds to a pattern value,
|
|
||||||
// and each column specifies the index of A, B, X, Y.
|
|
||||||
unsigned OpIdx[4][4] = {
|
|
||||||
{ 1, 1, 2, 2 },
|
|
||||||
{ 1, 2, 2, 1 },
|
|
||||||
{ 2, 1, 1, 2 },
|
|
||||||
{ 2, 2, 1, 1 }
|
|
||||||
};
|
|
||||||
|
|
||||||
MachineOperand &OpA = Prev.getOperand(OpIdx[Pattern][0]);
|
|
||||||
MachineOperand &OpB = Root.getOperand(OpIdx[Pattern][1]);
|
|
||||||
MachineOperand &OpX = Prev.getOperand(OpIdx[Pattern][2]);
|
|
||||||
MachineOperand &OpY = Root.getOperand(OpIdx[Pattern][3]);
|
|
||||||
MachineOperand &OpC = Root.getOperand(0);
|
|
||||||
|
|
||||||
unsigned RegA = OpA.getReg();
|
|
||||||
unsigned RegB = OpB.getReg();
|
|
||||||
unsigned RegX = OpX.getReg();
|
|
||||||
unsigned RegY = OpY.getReg();
|
|
||||||
unsigned RegC = OpC.getReg();
|
|
||||||
|
|
||||||
if (TargetRegisterInfo::isVirtualRegister(RegA))
|
|
||||||
MRI.constrainRegClass(RegA, RC);
|
|
||||||
if (TargetRegisterInfo::isVirtualRegister(RegB))
|
|
||||||
MRI.constrainRegClass(RegB, RC);
|
|
||||||
if (TargetRegisterInfo::isVirtualRegister(RegX))
|
|
||||||
MRI.constrainRegClass(RegX, RC);
|
|
||||||
if (TargetRegisterInfo::isVirtualRegister(RegY))
|
|
||||||
MRI.constrainRegClass(RegY, RC);
|
|
||||||
if (TargetRegisterInfo::isVirtualRegister(RegC))
|
|
||||||
MRI.constrainRegClass(RegC, RC);
|
|
||||||
|
|
||||||
// Create a new virtual register for the result of (X op Y) instead of
|
|
||||||
// recycling RegB because the MachineCombiner's computation of the critical
|
|
||||||
// path requires a new register definition rather than an existing one.
|
|
||||||
unsigned NewVR = MRI.createVirtualRegister(RC);
|
|
||||||
InstrIdxForVirtReg.insert(std::make_pair(NewVR, 0));
|
|
||||||
|
|
||||||
unsigned Opcode = Root.getOpcode();
|
|
||||||
bool KillA = OpA.isKill();
|
|
||||||
bool KillX = OpX.isKill();
|
|
||||||
bool KillY = OpY.isKill();
|
|
||||||
|
|
||||||
// Create new instructions for insertion.
|
|
||||||
MachineInstrBuilder MIB1 =
|
|
||||||
BuildMI(*MF, Prev.getDebugLoc(), TII->get(Opcode), NewVR)
|
|
||||||
.addReg(RegX, getKillRegState(KillX))
|
|
||||||
.addReg(RegY, getKillRegState(KillY));
|
|
||||||
MachineInstrBuilder MIB2 =
|
|
||||||
BuildMI(*MF, Root.getDebugLoc(), TII->get(Opcode), RegC)
|
|
||||||
.addReg(RegA, getKillRegState(KillA))
|
|
||||||
.addReg(NewVR, getKillRegState(true));
|
|
||||||
|
|
||||||
setSpecialOperandAttr(Root, Prev, *MIB1, *MIB2);
|
|
||||||
|
|
||||||
// Record new instructions for insertion and old instructions for deletion.
|
|
||||||
InsInstrs.push_back(MIB1);
|
|
||||||
InsInstrs.push_back(MIB2);
|
|
||||||
DelInstrs.push_back(&Prev);
|
|
||||||
DelInstrs.push_back(&Root);
|
|
||||||
}
|
|
||||||
|
|
||||||
void X86InstrInfo::genAlternativeCodeSequence(
|
|
||||||
MachineInstr &Root,
|
|
||||||
MachineCombinerPattern::MC_PATTERN Pattern,
|
|
||||||
SmallVectorImpl<MachineInstr *> &InsInstrs,
|
|
||||||
SmallVectorImpl<MachineInstr *> &DelInstrs,
|
|
||||||
DenseMap<unsigned, unsigned> &InstIdxForVirtReg) const {
|
|
||||||
MachineRegisterInfo &MRI = Root.getParent()->getParent()->getRegInfo();
|
|
||||||
|
|
||||||
// Select the previous instruction in the sequence based on the input pattern.
|
|
||||||
MachineInstr *Prev = nullptr;
|
|
||||||
switch (Pattern) {
|
|
||||||
case MachineCombinerPattern::MC_REASSOC_AX_BY:
|
|
||||||
case MachineCombinerPattern::MC_REASSOC_XA_BY:
|
|
||||||
Prev = MRI.getUniqueVRegDef(Root.getOperand(1).getReg());
|
|
||||||
break;
|
|
||||||
case MachineCombinerPattern::MC_REASSOC_AX_YB:
|
|
||||||
case MachineCombinerPattern::MC_REASSOC_XA_YB:
|
|
||||||
Prev = MRI.getUniqueVRegDef(Root.getOperand(2).getReg());
|
|
||||||
}
|
|
||||||
assert(Prev && "Unknown pattern for machine combiner");
|
|
||||||
|
|
||||||
reassociateOps(Root, *Prev, Pattern, InsInstrs, DelInstrs, InstIdxForVirtReg);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<unsigned, unsigned>
|
std::pair<unsigned, unsigned>
|
||||||
X86InstrInfo::decomposeMachineOperandsTargetFlags(unsigned TF) const {
|
X86InstrInfo::decomposeMachineOperandsTargetFlags(unsigned TF) const {
|
||||||
return std::make_pair(TF, 0u);
|
return std::make_pair(TF, 0u);
|
||||||
|
@ -26,19 +26,6 @@ namespace llvm {
|
|||||||
class X86RegisterInfo;
|
class X86RegisterInfo;
|
||||||
class X86Subtarget;
|
class X86Subtarget;
|
||||||
|
|
||||||
namespace MachineCombinerPattern {
|
|
||||||
enum MC_PATTERN : int {
|
|
||||||
// These are commutative variants for reassociating a computation chain
|
|
||||||
// of the form:
|
|
||||||
// B = A op X (Prev)
|
|
||||||
// C = B op Y (Root)
|
|
||||||
MC_REASSOC_AX_BY = 0,
|
|
||||||
MC_REASSOC_AX_YB = 1,
|
|
||||||
MC_REASSOC_XA_BY = 2,
|
|
||||||
MC_REASSOC_XA_YB = 3,
|
|
||||||
};
|
|
||||||
} // end namespace MachineCombinerPattern
|
|
||||||
|
|
||||||
namespace X86 {
|
namespace X86 {
|
||||||
// X86 specific condition code. These correspond to X86_*_COND in
|
// X86 specific condition code. These correspond to X86_*_COND in
|
||||||
// X86InstrInfo.td. They must be kept in synch.
|
// X86InstrInfo.td. They must be kept in synch.
|
||||||
@ -451,26 +438,19 @@ public:
|
|||||||
const MachineInstr *DefMI, unsigned DefIdx,
|
const MachineInstr *DefMI, unsigned DefIdx,
|
||||||
const MachineInstr *UseMI,
|
const MachineInstr *UseMI,
|
||||||
unsigned UseIdx) const override;
|
unsigned UseIdx) const override;
|
||||||
|
|
||||||
|
|
||||||
bool useMachineCombiner() const override {
|
bool useMachineCombiner() const override {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return true when there is potentially a faster code sequence
|
bool isAssociativeAndCommutative(const MachineInstr &Inst) const override;
|
||||||
/// for an instruction chain ending in <Root>. All potential patterns are
|
|
||||||
/// output in the <Pattern> array.
|
bool hasReassociableOperands(const MachineInstr &Inst,
|
||||||
bool getMachineCombinerPatterns(
|
const MachineBasicBlock *MBB) const override;
|
||||||
MachineInstr &Root,
|
|
||||||
SmallVectorImpl<MachineCombinerPattern::MC_PATTERN> &P) const override;
|
void setSpecialOperandAttr(MachineInstr &OldMI1, MachineInstr &OldMI2,
|
||||||
|
MachineInstr &NewMI1,
|
||||||
/// When getMachineCombinerPatterns() finds a pattern, this function generates
|
MachineInstr &NewMI2) const override;
|
||||||
/// the instructions that could replace the original code sequence.
|
|
||||||
void genAlternativeCodeSequence(
|
|
||||||
MachineInstr &Root, MachineCombinerPattern::MC_PATTERN P,
|
|
||||||
SmallVectorImpl<MachineInstr *> &InsInstrs,
|
|
||||||
SmallVectorImpl<MachineInstr *> &DelInstrs,
|
|
||||||
DenseMap<unsigned, unsigned> &InstrIdxForVirtReg) const override;
|
|
||||||
|
|
||||||
/// analyzeCompare - For a comparison instruction, return the source registers
|
/// analyzeCompare - For a comparison instruction, return the source registers
|
||||||
/// in SrcReg and SrcReg2 if having two register operands, and the value it
|
/// in SrcReg and SrcReg2 if having two register operands, and the value it
|
||||||
|
Loading…
x
Reference in New Issue
Block a user