Index: include/llvm/Target/TargetInstrInfo.h =================================================================== --- include/llvm/Target/TargetInstrInfo.h +++ include/llvm/Target/TargetInstrInfo.h @@ -84,17 +84,32 @@ const TargetRegisterInfo *TRI, const MachineFunction &MF) const; + /// An instruction that pollutes additional registers might still be + /// rematerializable under the assumption that those registers aren't live. + /// This is the purpose of YES_BUT_EXTRA_DEFS. + enum class Rematerializability + { + NO = 0, + YES_BUT_EXTRA_DEFS = 1, + YES = 2 + }; + /// Return true if the instruction is trivially rematerializable, meaning it /// has no side effects and requires no operands that aren't always available. /// This means the only allowed uses are constants and unallocatable physical /// registers so that the instructions result is independent of the place /// in the function. - bool isTriviallyReMaterializable(const MachineInstr &MI, - AliasAnalysis *AA = nullptr) const { - return MI.getOpcode() == TargetOpcode::IMPLICIT_DEF || - (MI.getDesc().isRematerializable() && - (isReallyTriviallyReMaterializable(MI, AA) || - isReallyTriviallyReMaterializableGeneric(MI, AA))); + Rematerializability + isTriviallyReMaterializable(const MachineInstr &MI, + AliasAnalysis *AA = nullptr) const { + if(MI.getOpcode() == TargetOpcode::IMPLICIT_DEF) + return Rematerializability::YES; + else if(!MI.getDesc().isRematerializable()) + return Rematerializability::NO; + else if(isReallyTriviallyReMaterializable(MI, AA)) + return Rematerializability::YES; + else + return isReallyTriviallyReMaterializableGeneric(MI, AA); } protected: @@ -149,8 +164,9 @@ /// set and the target hook isReallyTriviallyReMaterializable returns false, /// this function does target-independent tests to determine if the /// instruction is really trivially rematerializable. - bool isReallyTriviallyReMaterializableGeneric(const MachineInstr &MI, - AliasAnalysis *AA) const; + Rematerializability + isReallyTriviallyReMaterializableGeneric(const MachineInstr &MI, + AliasAnalysis *AA) const; public: /// These methods return the opcode of the frame setup/destroy instructions Index: lib/CodeGen/CalcSpillWeights.cpp =================================================================== --- lib/CodeGen/CalcSpillWeights.cpp +++ lib/CodeGen/CalcSpillWeights.cpp @@ -121,7 +121,8 @@ } } - if (!TII.isTriviallyReMaterializable(*MI, LIS.getAliasAnalysis())) + if (TII.isTriviallyReMaterializable(*MI, LIS.getAliasAnalysis()) + == TargetInstrInfo::Rematerializability::NO) return false; } return true; Index: lib/CodeGen/LiveRangeEdit.cpp =================================================================== --- lib/CodeGen/LiveRangeEdit.cpp +++ lib/CodeGen/LiveRangeEdit.cpp @@ -70,7 +70,8 @@ AliasAnalysis *aa) { assert(DefMI && "Missing instruction"); ScannedRemattable = true; - if (!TII.isTriviallyReMaterializable(*DefMI, aa)) + if (TII.isTriviallyReMaterializable(*DefMI, aa) + == TargetInstrInfo::Rematerializability::NO) return false; Remattable.insert(VNI); return true; @@ -152,6 +153,38 @@ if (cheapAsAMove && !TII.isAsCheapAsAMove(*RM.OrigMI)) return false; + // The instruction passed the checkRematerializable criterions. Now + // that we know the context, we need to make sure the instruction does + // not def any additional live registers. + if (TII.isTriviallyReMaterializable(*RM.OrigMI, nullptr) + == TargetInstrInfo::Rematerializability::YES_BUT_EXTRA_DEFS) + { + for(auto& MO : RM.OrigMI->defs()) { + unsigned Reg = MO.getReg(); + + // Check for a well-behaved physical register. + if (TargetRegisterInfo::isPhysicalRegister(Reg)) { + // A physreg def. We need to make sure the register is dead. + SlotIndexes *Indexes; + MachineInstr *Instruction; + MachineBasicBlock *BasicBlock; + + // The interaction with the register allocator isn't entirely clear + // to me, so to be on the safe side, never assume registers to be + // dead if they are allocatable. + if (MRI.isAllocatable(Reg) || + !(Indexes = LIS.getSlotIndexes()) || + !(Instruction = Indexes->getInstructionFromIndex(UseIdx)) || + !(BasicBlock = Instruction->getParent()) || + (BasicBlock->computeRegisterLiveness( + MRI.getTargetRegisterInfo(), Reg, Instruction) + != MachineBasicBlock::LivenessQueryResult::LQR_Dead)) { + return false; + } + } + } + } + // Verify that all used registers are available with the same values. if (!allUsesAvailableAt(RM.OrigMI, DefIdx, UseIdx)) return false; @@ -356,7 +389,9 @@ // the inst for remat of other siblings. The inst is saved in // LiveRangeEdit::DeadRemats and will be deleted after all the // allocations of the func are done. - if (isOrigDef && DeadRemats && TII.isTriviallyReMaterializable(*MI, AA)) { + if (isOrigDef && DeadRemats && + TII.isTriviallyReMaterializable(*MI, AA) + == TargetInstrInfo::Rematerializability::YES) { LiveInterval &NewLI = createEmptyIntervalFrom(Dest); NewLI.removeEmptySubRanges(); VNInfo *VNI = NewLI.getNextValue(Idx, LIS.getVNInfoAllocator()); Index: lib/CodeGen/MachineLICM.cpp =================================================================== --- lib/CodeGen/MachineLICM.cpp +++ lib/CodeGen/MachineLICM.cpp @@ -1088,7 +1088,8 @@ // Rematerializable instructions should always be hoisted since the register // allocator can just pull them down again when needed. - if (TII->isTriviallyReMaterializable(MI, AA)) + if (TII->isTriviallyReMaterializable(MI, AA) + != TargetInstrInfo::Rematerializability::NO) return true; // FIXME: If there are long latency loop-invariant instructions inside the @@ -1141,7 +1142,8 @@ // High register pressure situation, only hoist if the instruction is going // to be remat'ed. - if (!TII->isTriviallyReMaterializable(MI, AA) && + if (TII->isTriviallyReMaterializable(MI, AA) + == TargetInstrInfo::Rematerializability::NO && !MI.isDereferenceableInvariantLoad(AA)) { DEBUG(dbgs() << "Can't remat / high reg-pressure: " << MI); return false; Index: lib/CodeGen/RegisterCoalescer.cpp =================================================================== --- lib/CodeGen/RegisterCoalescer.cpp +++ lib/CodeGen/RegisterCoalescer.cpp @@ -1064,7 +1064,8 @@ } if (!TII->isAsCheapAsAMove(*DefMI)) return false; - if (!TII->isTriviallyReMaterializable(*DefMI, AA)) + if (TII->isTriviallyReMaterializable(*DefMI, AA) + != TargetInstrInfo::Rematerializability::YES) return false; if (!definesFullReg(*DefMI, SrcReg)) return false; Index: lib/CodeGen/TargetInstrInfo.cpp =================================================================== --- lib/CodeGen/TargetInstrInfo.cpp +++ lib/CodeGen/TargetInstrInfo.cpp @@ -853,14 +853,15 @@ return NewMI; } -bool TargetInstrInfo::isReallyTriviallyReMaterializableGeneric( +TargetInstrInfo::Rematerializability +TargetInstrInfo::isReallyTriviallyReMaterializableGeneric( const MachineInstr &MI, AliasAnalysis *AA) const { const MachineFunction &MF = *MI.getParent()->getParent(); const MachineRegisterInfo &MRI = MF.getRegInfo(); // Remat clients assume operand 0 is the defined register. if (!MI.getNumOperands() || !MI.getOperand(0).isReg()) - return false; + return Rematerializability::NO; unsigned DefReg = MI.getOperand(0).getReg(); // A sub-register definition can only be rematerialized if the instruction @@ -869,7 +870,7 @@ // moved safely. if (TargetRegisterInfo::isVirtualRegister(DefReg) && MI.getOperand(0).getSubReg() && MI.readsVirtualRegister(DefReg)) - return false; + return Rematerializability::NO; // A load from a fixed stack slot can be rematerialized. This may be // redundant with subsequent checks, but it's target-independent, @@ -877,20 +878,24 @@ int FrameIdx = 0; if (isLoadFromStackSlot(MI, FrameIdx) && MF.getFrameInfo().isImmutableObjectIndex(FrameIdx)) - return true; + return Rematerializability::YES; // Avoid instructions obviously unsafe for remat. if (MI.isNotDuplicable() || MI.mayStore() || MI.hasUnmodeledSideEffects()) - return false; + return Rematerializability::NO; // Don't remat inline asm. We have no idea how expensive it is // even if it's side effect free. if (MI.isInlineAsm()) - return false; + return Rematerializability::NO; // Avoid instructions which load from potentially varying memory. if (MI.mayLoad() && !MI.isDereferenceableInvariantLoad(AA)) - return false; + return Rematerializability::NO; + + // Track whether the instruction pollutes any additional registers. + // if they are dead at the rematerialization location, it's still ok. + bool AdditionalDefs = false; // If any of the registers accessed are non-constant, conservatively assume // the instruction is not rematerializable. @@ -908,10 +913,11 @@ // and we can freely move its uses. Alternatively, if it's allocatable, // it could get allocated to something with a def during allocation. if (!MRI.isConstantPhysReg(Reg)) - return false; + return Rematerializability::NO; } else { - // A physreg def. We can't remat it. - return false; + // A physreg def. If the register is dead, we can still rematerialize. + // This will be checked in LiveRangeEdit::canRematerializeAt. + AdditionalDefs = true; } continue; } @@ -919,17 +925,18 @@ // Only allow one virtual-register def. There may be multiple defs of the // same virtual register, though. if (MO.isDef() && Reg != DefReg) - return false; + return Rematerializability::NO; // Don't allow any virtual-register uses. Rematting an instruction with // virtual register uses would length the live ranges of the uses, which // is not necessarily a good idea, certainly not "trivial". if (MO.isUse()) - return false; + return Rematerializability::NO; } // Everything checked out. - return true; + return AdditionalDefs ? Rematerializability::YES_BUT_EXTRA_DEFS + : Rematerializability::YES; } int TargetInstrInfo::getSPAdjust(const MachineInstr &MI) const { Index: lib/Target/ARM/ARMInstrThumb.td =================================================================== --- lib/Target/ARM/ARMInstrThumb.td +++ lib/Target/ARM/ARMInstrThumb.td @@ -1133,7 +1133,7 @@ [(set tGPR:$Rdn, (srl tGPR:$Rn, tGPR:$Rm))]>, Sched<[WriteALU]>; // Move register -let isMoveImm = 1 in +let isMoveImm = 1, isReMaterializable = 1 in def tMOVi8 : T1sI<(outs tGPR:$Rd), (ins imm0_255:$imm8), IIC_iMOVi, "mov", "\t$Rd, $imm8", [(set tGPR:$Rd, imm0_255:$imm8)]>, Index: test/CodeGen/Thumb/movi8remat.ll =================================================================== --- /dev/null +++ test/CodeGen/Thumb/movi8remat.ll @@ -0,0 +1,25 @@ +; RUN: llc < %s -mtriple=thumb-apple-darwin | FileCheck %s + +declare void @consume_value(i32) #1 + +declare i32 @get_value(...) #1 + +declare void @consume_three_values(i32, i32, i32) #1 + +define void @should_not_spill() #0 { + tail call void @consume_value(i32 42) #2 + %1 = tail call i32 (...) @get_value() #2 + %2 = tail call i32 (...) @get_value() #2 + %3 = tail call i32 (...) @get_value() #2 + tail call void @consume_value(i32 %1) #2 + tail call void @consume_value(i32 %2) #2 + tail call void @consume_value(i32 %3) #2 + tail call void @consume_value(i32 42) #2 + tail call void @consume_three_values(i32 %1, i32 %2, i32 %3) #2 + ret void +} + +; CHECK: movs r0, #42 +; CHECK-NOT: str r0 +; CHECK: bl +; CHECK: movs r0, #42