summaryrefslogtreecommitdiff
path: root/lib/Target/PowerPC/PPCVSXFMAMutate.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Target/PowerPC/PPCVSXFMAMutate.cpp')
-rw-r--r--lib/Target/PowerPC/PPCVSXFMAMutate.cpp68
1 files changed, 45 insertions, 23 deletions
diff --git a/lib/Target/PowerPC/PPCVSXFMAMutate.cpp b/lib/Target/PowerPC/PPCVSXFMAMutate.cpp
index 6b19a2f7118b2..7c22cb22bfa5f 100644
--- a/lib/Target/PowerPC/PPCVSXFMAMutate.cpp
+++ b/lib/Target/PowerPC/PPCVSXFMAMutate.cpp
@@ -38,8 +38,14 @@
using namespace llvm;
-static cl::opt<bool> DisableVSXFMAMutate("disable-ppc-vsx-fma-mutation",
-cl::desc("Disable VSX FMA instruction mutation"), cl::Hidden);
+// Temporarily disable FMA mutation by default, since it doesn't handle
+// cross-basic-block intervals well.
+// See: http://lists.llvm.org/pipermail/llvm-dev/2016-February/095669.html
+// http://reviews.llvm.org/D17087
+static cl::opt<bool> DisableVSXFMAMutate(
+ "disable-ppc-vsx-fma-mutation",
+ cl::desc("Disable VSX FMA instruction mutation"), cl::init(true),
+ cl::Hidden);
#define DEBUG_TYPE "ppc-vsx-fma-mutate"
@@ -99,7 +105,7 @@ protected:
// %RM<imp-use>; VSLRC:%vreg16,%vreg18,%vreg9
// and we remove: %vreg5<def> = COPY %vreg9; VSLRC:%vreg5,%vreg9
- SlotIndex FMAIdx = LIS->getInstructionIndex(MI);
+ SlotIndex FMAIdx = LIS->getInstructionIndex(*MI);
VNInfo *AddendValNo =
LIS->getInterval(MI->getOperand(1).getReg()).Query(FMAIdx).valueIn();
@@ -168,21 +174,32 @@ protected:
if (OtherUsers || KillsAddendSrc)
continue;
- // Find one of the product operands that is killed by this instruction.
+ // The transformation doesn't work well with things like:
+ // %vreg5 = A-form-op %vreg5, %vreg11, %vreg5;
+ // unless vreg11 is also a kill, so skip when it is not,
+ // and check operand 3 to see it is also a kill to handle the case:
+ // %vreg5 = A-form-op %vreg5, %vreg5, %vreg11;
+ // where vreg5 and vreg11 are both kills. This case would be skipped
+ // otherwise.
+ unsigned OldFMAReg = MI->getOperand(0).getReg();
+
+ // Find one of the product operands that is killed by this instruction.
unsigned KilledProdOp = 0, OtherProdOp = 0;
- if (LIS->getInterval(MI->getOperand(2).getReg())
- .Query(FMAIdx).isKill()) {
+ unsigned Reg2 = MI->getOperand(2).getReg();
+ unsigned Reg3 = MI->getOperand(3).getReg();
+ if (LIS->getInterval(Reg2).Query(FMAIdx).isKill()
+ && Reg2 != OldFMAReg) {
KilledProdOp = 2;
OtherProdOp = 3;
- } else if (LIS->getInterval(MI->getOperand(3).getReg())
- .Query(FMAIdx).isKill()) {
+ } else if (LIS->getInterval(Reg3).Query(FMAIdx).isKill()
+ && Reg3 != OldFMAReg) {
KilledProdOp = 3;
OtherProdOp = 2;
}
- // If there are no killed product operands, then this transformation is
- // likely not profitable.
+ // If there are no usable killed product operands, then this
+ // transformation is likely not profitable.
if (!KilledProdOp)
continue;
@@ -212,14 +229,6 @@ protected:
bool KilledProdRegUndef = MI->getOperand(KilledProdOp).isUndef();
bool OtherProdRegUndef = MI->getOperand(OtherProdOp).isUndef();
- unsigned OldFMAReg = MI->getOperand(0).getReg();
-
- // The transformation doesn't work well with things like:
- // %vreg5 = A-form-op %vreg5, %vreg11, %vreg5;
- // so leave such things alone.
- if (OldFMAReg == KilledProdReg)
- continue;
-
// If there isn't a class that fits, we can't perform the transform.
// This is needed for correctness with a mixture of VSX and Altivec
// instructions to make sure that a low VSX register is not assigned to
@@ -236,23 +245,33 @@ protected:
MI->getOperand(0).setReg(KilledProdReg);
MI->getOperand(1).setReg(KilledProdReg);
MI->getOperand(3).setReg(AddendSrcReg);
- MI->getOperand(2).setReg(OtherProdReg);
MI->getOperand(0).setSubReg(KilledProdSubReg);
MI->getOperand(1).setSubReg(KilledProdSubReg);
MI->getOperand(3).setSubReg(AddSubReg);
- MI->getOperand(2).setSubReg(OtherProdSubReg);
MI->getOperand(1).setIsKill(KilledProdRegKill);
MI->getOperand(3).setIsKill(AddRegKill);
- MI->getOperand(2).setIsKill(OtherProdRegKill);
MI->getOperand(1).setIsUndef(KilledProdRegUndef);
MI->getOperand(3).setIsUndef(AddRegUndef);
- MI->getOperand(2).setIsUndef(OtherProdRegUndef);
MI->setDesc(TII->get(AltOpc));
+ // If the addend is also a multiplicand, replace it with the addend
+ // source in both places.
+ if (OtherProdReg == AddendMI->getOperand(0).getReg()) {
+ MI->getOperand(2).setReg(AddendSrcReg);
+ MI->getOperand(2).setSubReg(AddSubReg);
+ MI->getOperand(2).setIsKill(AddRegKill);
+ MI->getOperand(2).setIsUndef(AddRegUndef);
+ } else {
+ MI->getOperand(2).setReg(OtherProdReg);
+ MI->getOperand(2).setSubReg(OtherProdSubReg);
+ MI->getOperand(2).setIsKill(OtherProdRegKill);
+ MI->getOperand(2).setIsUndef(OtherProdRegUndef);
+ }
+
DEBUG(dbgs() << " -> " << *MI);
// The killed product operand was killed here, so we can reuse it now
@@ -312,7 +331,7 @@ protected:
// Remove the (now unused) copy.
DEBUG(dbgs() << " removing: " << *AddendMI << '\n');
- LIS->RemoveMachineInstrFromMaps(AddendMI);
+ LIS->RemoveMachineInstrFromMaps(*AddendMI);
AddendMI->eraseFromParent();
Changed = true;
@@ -323,6 +342,9 @@ protected:
public:
bool runOnMachineFunction(MachineFunction &MF) override {
+ if (skipFunction(*MF.getFunction()))
+ return false;
+
// If we don't have VSX then go ahead and return without doing
// anything.
const PPCSubtarget &STI = MF.getSubtarget<PPCSubtarget>();