diff --git a/lib/CodeGen/TargetInstrInfoImpl.cpp b/lib/CodeGen/TargetInstrInfoImpl.cpp index 1cd42ca2ae0..f32678f12b0 100644 --- a/lib/CodeGen/TargetInstrInfoImpl.cpp +++ b/lib/CodeGen/TargetInstrInfoImpl.cpp @@ -362,13 +362,17 @@ isReallyTriviallyReMaterializableGeneric(const MachineInstr *MI, const TargetInstrInfo &TII = *TM.getInstrInfo(); const TargetRegisterInfo &TRI = *TM.getRegisterInfo(); + // Remat clients assume operand 0 is the defined register. + if (!MI->getNumOperands() || !MI->getOperand(0).isReg()) + return false; + unsigned DefReg = MI->getOperand(0).getReg(); + // A sub-register definition can only be rematerialized if the instruction // doesn't read the other parts of the register. Otherwise it is really a // read-modify-write operation on the full virtual register which cannot be // moved safely. - unsigned Reg = MI->getOperand(0).getReg(); - if (TargetRegisterInfo::isVirtualRegister(Reg) && - MI->getOperand(0).getSubReg() && MI->readsVirtualRegister(Reg)) + if (TargetRegisterInfo::isVirtualRegister(DefReg) && + MI->getOperand(0).getSubReg() && MI->readsVirtualRegister(DefReg)) return false; // A load from a fixed stack slot can be rematerialized. This may be @@ -430,8 +434,9 @@ isReallyTriviallyReMaterializableGeneric(const MachineInstr *MI, continue; } - // Only allow one virtual-register def, and that in the first operand. - if (MO.isDef() != (i == 0)) + // Only allow one virtual-register def. There may be multiple defs of the + // same virtual register, though. + if (MO.isDef() && Reg != DefReg) return false; // Don't allow any virtual-register uses. Rematting an instruction with diff --git a/test/CodeGen/ARM/subreg-remat.ll b/test/CodeGen/ARM/subreg-remat.ll index cf45c034514..993d7ec7505 100644 --- a/test/CodeGen/ARM/subreg-remat.ll +++ b/test/CodeGen/ARM/subreg-remat.ll @@ -26,3 +26,27 @@ define void @f1(float %x, <2 x float>* %p) { store <2 x float> %v2, <2 x float>* %p, align 8 ret void } + +; On the other hand, when the partial redef doesn't read the full register +; because the bits are undef, we should rematerialize. The vector is now built +; like this: +; +; %vreg2:ssub_0 = VLDRS , 0, pred:14, pred:%noreg, %vreg2; mem:LD4[ConstantPool] +; +; The extra operand indicates that the instruction fully defines the +; virtual register. It doesn't read the old value. +; +; CHECK: f2 +; CHECK: vldr.32 s0, LCPI +; The vector must not be spilled: +; CHECK-NOT: vstr.64 +; CHECK: asm clobber d0 +; But instead rematerialize after the asm: +; CHECK: vldr.32 [[S0:s[0-9]+]], LCPI +; CHECK: vstr.64 [[D0:d[0-9]+]], [r0] +define void @f2(<2 x float>* %p) { + %v2 = insertelement <2 x float> undef, float 0x400921FB60000000, i32 0 + %y = call double asm sideeffect "asm clobber $0", "=w,0,~{d1},~{d2},~{d3},~{d4},~{d5},~{d6},~{d7},~{d8},~{d9},~{d10},~{d11},~{d12},~{d13},~{d14},~{d15},~{d16},~{d17},~{d18},~{d19},~{d20},~{d21},~{d22},~{d23},~{d24},~{d25},~{d26},~{d27},~{d28},~{d29},~{d30},~{d31}"(<2 x float> %v2) nounwind + store <2 x float> %v2, <2 x float>* %p, align 8 + ret void +}