diff --git a/include/llvm/CodeGen/LiveIntervalAnalysis.h b/include/llvm/CodeGen/LiveIntervalAnalysis.h index 19865e59c1e..83d8d1dd4b1 100644 --- a/include/llvm/CodeGen/LiveIntervalAnalysis.h +++ b/include/llvm/CodeGen/LiveIntervalAnalysis.h @@ -233,6 +233,11 @@ namespace llvm { addIntervalsForSpills(const LiveInterval& i, const LoopInfo *loopInfo, VirtRegMap& vrm); + /// isReMaterializable - Returns true if every definition of MI of every + /// val# of the specified interval is re-materializable. Also returns true + /// by reference if all of the defs are load instructions. + bool isReMaterializable(const LiveInterval &li, bool &isLoad); + private: /// computeIntervals - Compute live intervals. void computeIntervals(); @@ -265,9 +270,10 @@ namespace llvm { LiveInterval &interval, bool isAlias = false); /// isReMaterializable - Returns true if the definition MI of the specified - /// val# of the specified interval is re-materializable. + /// val# of the specified interval is re-materializable. Also returns true + /// by reference if the def is a load. bool isReMaterializable(const LiveInterval &li, const VNInfo *ValNo, - MachineInstr *MI); + MachineInstr *MI, bool &isLoad); /// tryFoldMemoryOperand - Attempts to fold either a spill / restore from /// slot / to reg or any rematerialized load into ith operand of specified diff --git a/lib/CodeGen/LiveIntervalAnalysis.cpp b/lib/CodeGen/LiveIntervalAnalysis.cpp index a9e69483be4..92627345ded 100644 --- a/lib/CodeGen/LiveIntervalAnalysis.cpp +++ b/lib/CodeGen/LiveIntervalAnalysis.cpp @@ -607,12 +607,16 @@ LiveInterval LiveIntervals::createInterval(unsigned reg) { /// isReMaterializable - Returns true if the definition MI of the specified /// val# of the specified interval is re-materializable. bool LiveIntervals::isReMaterializable(const LiveInterval &li, - const VNInfo *ValNo, MachineInstr *MI) { + const VNInfo *ValNo, MachineInstr *MI, + bool &isLoad) { if (DisableReMat) return false; - if (tii_->isTriviallyReMaterializable(MI)) + isLoad = false; + if (tii_->isTriviallyReMaterializable(MI)) { + isLoad = MI->getInstrDescriptor()->Flags & M_LOAD_FLAG; return true; + } int FrameIdx = 0; if (!tii_->isLoadFromStackSlot(MI, FrameIdx) || @@ -621,6 +625,7 @@ bool LiveIntervals::isReMaterializable(const LiveInterval &li, // This is a load from fixed stack slot. It can be rematerialized unless it's // re-defined by a two-address instruction. + isLoad = true; for (LiveInterval::const_vni_iterator i = li.vni_begin(), e = li.vni_end(); i != e; ++i) { const VNInfo *VNI = *i; @@ -631,8 +636,32 @@ bool LiveIntervals::isReMaterializable(const LiveInterval &li, continue; // Dead val#. MachineInstr *DefMI = (DefIdx == ~0u) ? NULL : getInstructionFromIndex(DefIdx); - if (DefMI && DefMI->isRegReDefinedByTwoAddr(li.reg)) + if (DefMI && DefMI->isRegReDefinedByTwoAddr(li.reg)) { + isLoad = false; return false; + } + } + return true; +} + +/// isReMaterializable - Returns true if every definition of MI of every +/// val# of the specified interval is re-materializable. +bool LiveIntervals::isReMaterializable(const LiveInterval &li, bool &isLoad) { + isLoad = false; + for (LiveInterval::const_vni_iterator i = li.vni_begin(), e = li.vni_end(); + i != e; ++i) { + const VNInfo *VNI = *i; + unsigned DefIdx = VNI->def; + if (DefIdx == ~1U) + continue; // Dead val#. + // Is the def for the val# rematerializable? + if (DefIdx == ~0u) + return false; + MachineInstr *ReMatDefMI = getInstructionFromIndex(DefIdx); + bool DefIsLoad = false; + if (!ReMatDefMI || !isReMaterializable(li, VNI, ReMatDefMI, DefIsLoad)) + return false; + isLoad |= DefIsLoad; } return true; } @@ -1225,7 +1254,8 @@ addIntervalsForSpills(const LiveInterval &li, // Is the def for the val# rematerializable? MachineInstr *ReMatDefMI = (DefIdx == ~0u) ? 0 : getInstructionFromIndex(DefIdx); - if (ReMatDefMI && isReMaterializable(li, VNI, ReMatDefMI)) { + bool dummy; + if (ReMatDefMI && isReMaterializable(li, VNI, ReMatDefMI, dummy)) { // Remember how to remat the def of this val#. ReMatOrigDefs[VN] = ReMatDefMI; // Original def may be modified so we have to make a copy here. vrm must diff --git a/lib/CodeGen/SimpleRegisterCoalescing.cpp b/lib/CodeGen/SimpleRegisterCoalescing.cpp index 3d2669becd4..6eec5ab885c 100644 --- a/lib/CodeGen/SimpleRegisterCoalescing.cpp +++ b/lib/CodeGen/SimpleRegisterCoalescing.cpp @@ -1485,6 +1485,20 @@ bool SimpleRegisterCoalescing::runOnMachineFunction(MachineFunction &fn) { // it and hope it will be easier to allocate for this li. if (isZeroLengthInterval(&LI)) LI.weight = HUGE_VALF; + else { + bool isLoad = false; + if (li_->isReMaterializable(LI, isLoad)) { + // If all of the definitions of the interval are re-materializable, + // it is a preferred candidate for spilling. If non of the defs are + // loads, then it's potentially very cheap to re-materialize. + // FIXME: this gets much more complicated once we support non-trivial + // re-materialization. + if (isLoad) + LI.weight *= 0.9F; + else + LI.weight *= 0.5F; + } + } // Slightly prefer live interval that has been assigned a preferred reg. if (LI.preference) diff --git a/test/CodeGen/ARM/lsr-code-insertion.ll b/test/CodeGen/ARM/lsr-code-insertion.ll index 507c8912920..3881e91453b 100644 --- a/test/CodeGen/ARM/lsr-code-insertion.ll +++ b/test/CodeGen/ARM/lsr-code-insertion.ll @@ -1,4 +1,5 @@ -; RUN: llvm-as < %s | llc -stats |& grep {40.*Number of machine instrs printed} +; RUN: llvm-as < %s | llc -stats |& grep {39.*Number of machine instrs printed} +; RUN: llvm-as < %s | llc -stats |& grep {.*Number of re-materialization} ; This test really wants to check that the resultant "cond_true" block only ; has a single store in it, and that cond_true55 only has code to materialize ; the constant and do a store. We do *not* want something like this: @@ -7,7 +8,6 @@ ; add r8, r0, r6 ; str r10, [r8, #+4] ; -; XFAIL: * target triple = "arm-apple-darwin8" define void @foo(i32* %mc, i32* %mpp, i32* %ip, i32* %dpp, i32* %tpmm, i32 %M, i32* %tpim, i32* %tpdm, i32* %bp, i32* %ms, i32 %xmb) {