From d41474d2c09a9fd0d1251554b920a783839b2787 Mon Sep 17 00:00:00 2001 From: Evan Cheng Date: Tue, 30 Sep 2008 06:36:58 +0000 Subject: [PATCH] If a re-materializable instruction has a register operand, the spiller will change the register operand's spill weight to HUGE_VAL to avoid it being spilled. However, if the operand is already in the queue ready to be spilled, avoid re-materializing it. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@56835 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/LiveIntervalAnalysis.cpp | 20 ++++-- lib/CodeGen/RegAllocLinearScan.cpp | 5 +- lib/CodeGen/SimpleRegisterCoalescing.cpp | 3 +- test/CodeGen/X86/2008-09-29-ReMatBug.ll | 85 ++++++++++++++++++++++++ 4 files changed, 105 insertions(+), 8 deletions(-) create mode 100644 test/CodeGen/X86/2008-09-29-ReMatBug.ll diff --git a/lib/CodeGen/LiveIntervalAnalysis.cpp b/lib/CodeGen/LiveIntervalAnalysis.cpp index bc66321b4af..4ed456bf11a 100644 --- a/lib/CodeGen/LiveIntervalAnalysis.cpp +++ b/lib/CodeGen/LiveIntervalAnalysis.cpp @@ -819,6 +819,7 @@ bool LiveIntervals::isValNoAvailableAt(const LiveInterval &li, MachineInstr *MI, /// val# of the specified interval is re-materializable. bool LiveIntervals::isReMaterializable(const LiveInterval &li, const VNInfo *ValNo, MachineInstr *MI, + SmallVectorImpl &SpillIs, bool &isLoad) { if (DisableReMat) return false; @@ -855,8 +856,8 @@ bool LiveIntervals::isReMaterializable(const LiveInterval &li, // If the instruction accesses memory and the memory could be non-constant, // assume the instruction is not rematerializable. - for (std::list::const_iterator I = MI->memoperands_begin(), - E = MI->memoperands_end(); I != E; ++I) { + for (std::list::const_iterator + I = MI->memoperands_begin(), E = MI->memoperands_end(); I != E; ++I){ const MachineMemOperand &MMO = *I; if (MMO.isVolatile() || MMO.isStore()) return false; @@ -924,13 +925,21 @@ bool LiveIntervals::isReMaterializable(const LiveInterval &li, if (!isValNoAvailableAt(ImpLi, MI, UseIdx)) return false; } + + // If a register operand of the re-materialized instruction is going to + // be spilled next, then it's not legal to re-materialize this instruction. + for (unsigned i = 0, e = SpillIs.size(); i != e; ++i) + if (ImpUse == SpillIs[i]->reg) + 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) { +bool LiveIntervals::isReMaterializable(const LiveInterval &li, + SmallVectorImpl &SpillIs, + bool &isLoad) { isLoad = false; for (LiveInterval::const_vni_iterator i = li.vni_begin(), e = li.vni_end(); i != e; ++i) { @@ -944,7 +953,7 @@ bool LiveIntervals::isReMaterializable(const LiveInterval &li, bool &isLoad) { MachineInstr *ReMatDefMI = getInstructionFromIndex(DefIdx); bool DefIsLoad = false; if (!ReMatDefMI || - !isReMaterializable(li, VNI, ReMatDefMI, DefIsLoad)) + !isReMaterializable(li, VNI, ReMatDefMI, SpillIs, DefIsLoad)) return false; isLoad |= DefIsLoad; } @@ -1728,6 +1737,7 @@ addIntervalsForSpillsFast(const LiveInterval &li, std::vector LiveIntervals:: addIntervalsForSpills(const LiveInterval &li, + SmallVectorImpl &SpillIs, const MachineLoopInfo *loopInfo, VirtRegMap &vrm, float &SSWeight) { @@ -1831,7 +1841,7 @@ addIntervalsForSpills(const LiveInterval &li, MachineInstr *ReMatDefMI = (DefIdx == ~0u) ? 0 : getInstructionFromIndex(DefIdx); bool dummy; - if (ReMatDefMI && isReMaterializable(li, VNI, ReMatDefMI, dummy)) { + if (ReMatDefMI && isReMaterializable(li, VNI, ReMatDefMI, SpillIs, 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. diff --git a/lib/CodeGen/RegAllocLinearScan.cpp b/lib/CodeGen/RegAllocLinearScan.cpp index d834031ae6b..7291e12bbea 100644 --- a/lib/CodeGen/RegAllocLinearScan.cpp +++ b/lib/CodeGen/RegAllocLinearScan.cpp @@ -879,8 +879,9 @@ void RALinScan::assignRegOrStackSlotAtInterval(LiveInterval* cur) if (cur->weight != HUGE_VALF && cur->weight <= minWeight) { DOUT << "\t\t\tspilling(c): " << *cur << '\n'; float SSWeight; + SmallVector spillIs; std::vector added = - li_->addIntervalsForSpills(*cur, loopInfo, *vrm_, SSWeight); + li_->addIntervalsForSpills(*cur, spillIs, loopInfo, *vrm_, SSWeight); addStackInterval(cur, ls_, li_, SSWeight, *vrm_); if (added.empty()) return; // Early exit if all spills were folded. @@ -931,7 +932,7 @@ void RALinScan::assignRegOrStackSlotAtInterval(LiveInterval* cur) earliestStart = std::min(earliestStart, sli->beginNumber()); float SSWeight; std::vector newIs = - li_->addIntervalsForSpills(*sli, loopInfo, *vrm_, SSWeight); + li_->addIntervalsForSpills(*sli, spillIs, loopInfo, *vrm_, SSWeight); addStackInterval(sli, ls_, li_, SSWeight, *vrm_); std::copy(newIs.begin(), newIs.end(), std::back_inserter(added)); spilled.insert(sli->reg); diff --git a/lib/CodeGen/SimpleRegisterCoalescing.cpp b/lib/CodeGen/SimpleRegisterCoalescing.cpp index bdc37b16b6a..86065f069f7 100644 --- a/lib/CodeGen/SimpleRegisterCoalescing.cpp +++ b/lib/CodeGen/SimpleRegisterCoalescing.cpp @@ -2361,7 +2361,8 @@ bool SimpleRegisterCoalescing::runOnMachineFunction(MachineFunction &fn) { LI.weight = HUGE_VALF; else { bool isLoad = false; - if (li_->isReMaterializable(LI, isLoad)) { + SmallVector SpillIs; + if (li_->isReMaterializable(LI, SpillIs, 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. diff --git a/test/CodeGen/X86/2008-09-29-ReMatBug.ll b/test/CodeGen/X86/2008-09-29-ReMatBug.ll new file mode 100644 index 00000000000..d4da01a508f --- /dev/null +++ b/test/CodeGen/X86/2008-09-29-ReMatBug.ll @@ -0,0 +1,85 @@ +; RUN: llvm-as < %s | llc -mtriple=i386-apple-darwin -relocation-model=pic -disable-fp-elim + + %struct..0objc_selector = type opaque + %struct.NSString = type opaque + %struct.XCStringList = type { i32, %struct._XCStringListNode* } + %struct._XCStringListNode = type { [3 x i8], [0 x i8], i8 } + %struct.__builtin_CFString = type { i32*, i32, i8*, i32 } +internal constant %struct.__builtin_CFString { i32* getelementptr ([0 x i32]* @__CFConstantStringClassReference, i32 0, i32 0), i32 1992, i8* getelementptr ([3 x i8]* @"\01LC", i32 0, i32 0), i32 2 } ; <%struct.__builtin_CFString*>:0 [#uses=1] +@__CFConstantStringClassReference = external global [0 x i32] ; <[0 x i32]*> [#uses=1] +@"\01LC" = internal constant [3 x i8] c"NO\00" ; <[3 x i8]*> [#uses=1] +@"\01LC1" = internal constant [1 x i8] zeroinitializer ; <[1 x i8]*> [#uses=1] +@llvm.used1 = appending global [1 x i8*] [ i8* bitcast (%struct.NSString* (%struct.XCStringList*, %struct..0objc_selector*)* @"-[XCStringList stringRepresentation]" to i8*) ], section "llvm.metadata" ; <[1 x i8*]*> [#uses=0] + +define %struct.NSString* @"-[XCStringList stringRepresentation]"(%struct.XCStringList* %self, %struct..0objc_selector* %_cmd) nounwind { +entry: + %0 = load i32* null, align 4 ; [#uses=1] + %1 = and i32 %0, 16777215 ; [#uses=1] + %2 = icmp eq i32 %1, 0 ; [#uses=1] + br i1 %2, label %bb44, label %bb4 + +bb4: ; preds = %entry + %3 = load %struct._XCStringListNode** null, align 4 ; <%struct._XCStringListNode*> [#uses=2] + %4 = icmp eq %struct._XCStringListNode* %3, null ; [#uses=1] + %5 = bitcast %struct._XCStringListNode* %3 to i32* ; [#uses=1] + br label %bb37.outer + +bb6: ; preds = %bb37 + br label %bb19 + +bb19: ; preds = %bb37, %bb6 + %.rle = phi i32 [ 0, %bb6 ], [ %10, %bb37 ] ; [#uses=1] + %bufptr.0.lcssa = phi i8* [ null, %bb6 ], [ null, %bb37 ] ; [#uses=2] + %6 = and i32 %.rle, 16777215 ; [#uses=1] + %7 = icmp eq i32 %6, 0 ; [#uses=1] + br i1 %7, label %bb25.split, label %bb37 + +bb25.split: ; preds = %bb19 + call void @foo(i8* getelementptr ([1 x i8]* @"\01LC1", i32 0, i32 0)) nounwind nounwind + br label %bb35.outer + +bb34: ; preds = %bb35, %bb35, %bb35, %bb35 + %8 = getelementptr i8* %bufptr.0.lcssa, i32 %totalLength.0.ph ; [#uses=1] + store i8 92, i8* %8, align 1 + br label %bb35.outer + +bb35.outer: ; preds = %bb34, %bb25.split + %totalLength.0.ph = add i32 0, %totalLength.1.ph ; [#uses=2] + br label %bb35 + +bb35: ; preds = %bb35, %bb35.outer + %9 = load i8* null, align 1 ; [#uses=1] + switch i8 %9, label %bb35 [ + i8 0, label %bb37.outer + i8 32, label %bb34 + i8 92, label %bb34 + i8 34, label %bb34 + i8 39, label %bb34 + ] + +bb37.outer: ; preds = %bb35, %bb4 + %totalLength.1.ph = phi i32 [ 0, %bb4 ], [ %totalLength.0.ph, %bb35 ] ; [#uses=1] + %bufptr.1.ph = phi i8* [ null, %bb4 ], [ %bufptr.0.lcssa, %bb35 ] ; [#uses=2] + br i1 %4, label %bb39.split, label %bb37 + +bb37: ; preds = %bb37.outer, %bb19 + %10 = load i32* %5, align 4 ; [#uses=1] + br i1 false, label %bb6, label %bb19 + +bb39.split: ; preds = %bb37.outer + %11 = bitcast i8* null to %struct.NSString* ; <%struct.NSString*> [#uses=2] + %12 = icmp eq i8* null, %bufptr.1.ph ; [#uses=1] + br i1 %12, label %bb44, label %bb42 + +bb42: ; preds = %bb39.split + call void @quux(i8* %bufptr.1.ph) nounwind nounwind + ret %struct.NSString* %11 + +bb44: ; preds = %bb39.split, %entry + %.0 = phi %struct.NSString* [ bitcast (%struct.__builtin_CFString* @0 to %struct.NSString*), %entry ], [ %11, %bb39.split ] ; <%struct.NSString*> [#uses=1] + ret %struct.NSString* %.0 +} + +declare void @foo(i8*) + +declare void @quux(i8*)