bool Changed = false;
MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
+ const TargetRegisterInfo *TRI = &TII->getRegisterInfo();
for (MachineBasicBlock::iterator I = MBB.begin(), IE = MBB.end();
I != IE; ++I) {
MachineInstr *MI = I;
// In theory, there could be other uses of the addend copy before this
// fma. We could deal with this, but that would require additional
// logic below and I suspect it will not occur in any relevant
- // situations.
- bool OtherUsers = false;
+ // situations. Additionally, check whether the copy source is killed
+ // prior to the fma. In order to replace the addend here with the
+ // source of the copy, it must still be live here. We can't use
+ // interval testing for a physical register, so as long as we're
+ // walking the MIs we may as well test liveness here.
+ bool OtherUsers = false, KillsAddendSrc = false;
for (auto J = std::prev(I), JE = MachineBasicBlock::iterator(AddendMI);
- J != JE; --J)
+ J != JE; --J) {
if (J->readsVirtualRegister(AddendMI->getOperand(0).getReg())) {
OtherUsers = true;
break;
}
+ if (J->modifiesRegister(AddendSrcReg, TRI) ||
+ J->killsRegister(AddendSrcReg, TRI)) {
+ KillsAddendSrc = true;
+ break;
+ }
+ }
- if (OtherUsers)
+ if (OtherUsers || KillsAddendSrc)
continue;
// Find one of the product operands that is killed by this instruction.
if (!KilledProdOp)
continue;
- // In order to replace the addend here with the source of the copy,
- // it must still be live here.
- if (!LIS->getInterval(AddendMI->getOperand(1).getReg()).liveAt(FMAIdx))
- continue;
+ // For virtual registers, verify that the addend source register
+ // is live here (as should have been assured above).
+ if (TargetRegisterInfo::isVirtualRegister(AddendSrcReg))
+ assert(LIS->getInterval(AddendSrcReg).liveAt(FMAIdx) &&
+ "Addend source register is not available!");
// Transform: (O2 * O3) + O1 -> (O2 * O1) + O3.
-; RUN: llc < %s -march=ppc32 -fp-contract=fast | FileCheck %s
+; RUN: llc < %s -march=ppc32 -fp-contract=fast -mattr=-vsx | FileCheck %s
+; RUN: llc < %s -mtriple=powerpc64-unknown-linux-gnu -fp-contract=fast -mattr=+vsx | FileCheck -check-prefix=CHECK-VSX %s
declare double @dummy1(double) #0
declare double @dummy2(double, double) #0
; CHECK-LABEL: test_FMADD1:
; CHECK: fmadd
; CHECK-NEXT: blr
+
+; CHECK-VSX-LABEL: test_FMADD1:
+; CHECK-VSX: xsmaddmdp
+; CHECK-VSX-NEXT: blr
}
define double @test_FMADD2(double %A, double %B, double %C) {
; CHECK-LABEL: test_FMADD2:
; CHECK: fmadd
; CHECK-NEXT: blr
+
+; CHECK-VSX-LABEL: test_FMADD2:
+; CHECK-VSX: xsmaddmdp
+; CHECK-VSX-NEXT: blr
}
define double @test_FMSUB1(double %A, double %B, double %C) {
; CHECK-LABEL: test_FMSUB1:
; CHECK: fmsub
; CHECK-NEXT: blr
+
+; CHECK-VSX-LABEL: test_FMSUB1:
+; CHECK-VSX: xsmsubmdp
+; CHECK-VSX-NEXT: blr
}
define double @test_FMSUB2(double %A, double %B, double %C, double %D) {
; CHECK-LABEL: test_FMSUB2:
; CHECK: fmadd
; CHECK-NEXT: fmsub
+
+; CHECK-VSX-LABEL: test_FMSUB2:
+; CHECK-VSX: xsmaddadp
+; CHECK-VSX-NEXT: xsmsubmdp
}
define double @test_FNMADD1(double %A, double %B, double %C) {
; CHECK-LABEL: test_FNMADD1:
; CHECK: fnmadd
; CHECK-NEXT: blr
+
+; CHECK-VSX-LABEL: test_FNMADD1:
+; CHECK-VSX: xsnmaddmdp
+; CHECK-VSX-NEXT: blr
}
define double @test_FNMADD2(double %A, double %B, double %C) {
; CHECK-LABEL: test_FNMADD2:
; CHECK: fnmadd
; CHECK-NEXT: blr
+
+; CHECK-VSX-LABEL: test_FNMADD2:
+; CHECK-VSX: xsnmaddmdp
+; CHECK-VSX-NEXT: blr
}
define double @test_FNMSUB1(double %A, double %B, double %C) {
; CHECK-LABEL: test_FNMSUB1:
; CHECK: fnmsub
; CHECK-NEXT: blr
+
+; CHECK-VSX-LABEL: test_FNMSUB1:
+; CHECK-VSX: xsnmsubmdp
}
define double @test_FNMSUB2(double %A, double %B, double %C) {
; CHECK-LABEL: test_FNMSUB2:
; CHECK: fnmsub
; CHECK-NEXT: blr
+
+; CHECK-VSX-LABEL: test_FNMSUB2:
+; CHECK-VSX: xsnmsubmdp
+; CHECK-VSX-NEXT: blr
}
define float @test_FNMSUBS(float %A, float %B, float %C) {
; CHECK-LABEL: test_FNMSUBS:
; CHECK: fnmsubs
; CHECK-NEXT: blr
+
+; CHECK-VSX-LABEL: test_FNMSUBS:
+; CHECK-VSX: fnmsubs
+; CHECK-VSX-NEXT: blr
}