Index: lib/CodeGen/InlineSpiller.cpp =================================================================== --- lib/CodeGen/InlineSpiller.cpp +++ lib/CodeGen/InlineSpiller.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "Spiller.h" +#include "SplitKit.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/Statistic.h" @@ -68,6 +69,9 @@ const TargetRegisterInfo &TRI; const MachineBlockFrequencyInfo &MBFI; + // Used to find out LastSplitPoint of BB. + std::unique_ptr SA; + // Map from StackSlot to its original register. DenseMap StackSlotToReg; // Map from pair of (StackSlot and Original VNI) to a set of spills which @@ -1074,7 +1078,7 @@ bool HoistSpillHelper::isSpillCandBB(unsigned OrigReg, VNInfo &OrigVNI, MachineBasicBlock &BB, unsigned &LiveReg) { SlotIndex Idx; - MachineBasicBlock::iterator MI = BB.getFirstTerminator(); + MachineBasicBlock::iterator MI = SA->getLastSplitPointIter(&BB); if (MI != BB.end()) Idx = LIS.getInstructionIndex(*MI); else @@ -1358,6 +1362,7 @@ void HoistSpillHelper::hoistAllSpills() { SmallVector NewVRegs; LiveRangeEdit Edit(nullptr, NewVRegs, MF, LIS, &VRM, this); + SA.reset(new SplitAnalysis(VRM, LIS, Loops)); // Save the mapping between stackslot and its original reg. DenseMap SlotToOrigReg; @@ -1388,6 +1393,10 @@ dbgs() << "\n"; }); + LiveInterval &OrigLI = LIS.getInterval(OrigReg); + // Skip analyzeUses because SA is only used to get LastSplitPoint of BB. + SA->analyze(&OrigLI, true); + // SpillsToRm is the spill set to be removed from EqValSpills. SmallVector SpillsToRm; // SpillsToIns is the spill set to be newly inserted after hoisting. @@ -1407,17 +1416,15 @@ // Stack live range update. LiveInterval &StackIntvl = LSS.getInterval(Slot); - if (!SpillsToIns.empty() || !SpillsToRm.empty()) { - LiveInterval &OrigLI = LIS.getInterval(OrigReg); + if (!SpillsToIns.empty() || !SpillsToRm.empty()) StackIntvl.MergeValueInAsValue(OrigLI, OrigVNI, StackIntvl.getValNumInfo(0)); - } // Insert hoisted spills. for (auto const Insert : SpillsToIns) { MachineBasicBlock *BB = Insert.first; unsigned LiveReg = Insert.second; - MachineBasicBlock::iterator MI = BB->getFirstTerminator(); + MachineBasicBlock::iterator MI = SA->getLastSplitPointIter(BB); TII.storeRegToStackSlot(*BB, MI, LiveReg, false, Slot, MRI.getRegClass(LiveReg), &TRI); LIS.InsertMachineInstrRangeInMaps(std::prev(MI), MI); Index: lib/CodeGen/SplitKit.h =================================================================== --- lib/CodeGen/SplitKit.h +++ lib/CodeGen/SplitKit.h @@ -122,8 +122,8 @@ const MachineLoopInfo &mli); /// analyze - set CurLI to the specified interval, and analyze how it may be - /// split. - void analyze(const LiveInterval *li); + /// split. If SkipAnalyze is true, skip the analyzeUses call. + void analyze(const LiveInterval *li, bool SkipAnalyze = false); /// didRepairRange() - Returns true if CurLI was invalid and has been repaired /// by analyze(). This really shouldn't happen, but sometimes the coalescer Index: lib/CodeGen/SplitKit.cpp =================================================================== --- lib/CodeGen/SplitKit.cpp +++ lib/CodeGen/SplitKit.cpp @@ -307,10 +307,11 @@ return I != Orig.begin() && (--I)->end == Idx; } -void SplitAnalysis::analyze(const LiveInterval *li) { +void SplitAnalysis::analyze(const LiveInterval *li, bool SkipAnalyze) { clear(); CurLI = li; - analyzeUses(); + if (!SkipAnalyze) + analyzeUses(); } Index: test/CodeGen/X86/hoist-spill-lpad.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/hoist-spill-lpad.ll @@ -0,0 +1,134 @@ +; RUN: llc < %s | FileCheck %s +; +; PR27612. The following spill is hoisted from two locations: the fall +; through succ block and the landingpad block of a call which may throw +; exception. If it is not hoisted before the call, the spill will be +; missing on the landingpad path. +; +; CHECK-LABEL: _Z5CheckIZ4mainE3$_0EvT_: +; CHECK: movq %r14, 16(%rbx) # 8-byte Spill +; CHECK-NEXT: callq _ZlsIiEv1CIT_Ej + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +%class.basic_stringstream.2.110 = type { i8 } +%class.F.3.111 = type { i8 } +%class.A.1.109 = type { %class.allocator.0.108 } +%class.allocator.0.108 = type { i8 } + +@_ZTIi = external constant i8* +@llvm.global_ctors = external global [1 x { i32, void ()*, i8* }] +@__asan_option_detect_stack_use_after_return = external global i32 +@__asan_gen_ = external unnamed_addr constant [36 x i8], align 1 +@__asan_gen_.1 = external unnamed_addr constant [17 x i8], align 1 +@__asan_gen_.2 = external unnamed_addr constant [17 x i8], align 1 + +declare i32 @main() + +define internal fastcc void @"_Z5CheckIZ4mainE3$_0EvT_"() unnamed_addr personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { +entry: + br i1 undef, label %bb, label %bb1 + +bb: ; preds = %entry + %tmp = call i64 @__asan_stack_malloc_1(i64 96) + br label %bb1 + +bb1: ; preds = %bb, %entry + %tmp2 = phi i64 [ 0, %entry ], [ %tmp, %bb ] + br i1 undef, label %bb3, label %bb4 + +bb3: ; preds = %bb1 + %MyAlloca = alloca i8, i64 96, align 32 + br label %bb4 + +bb4: ; preds = %bb3, %bb1 + %tmp5 = phi i64 [ %tmp2, %bb1 ], [ 0, %bb3 ] + %tmp6 = add i64 %tmp5, 32 + %tmp7 = inttoptr i64 %tmp6 to %class.basic_stringstream.2.110* + %tmp8 = add i64 %tmp5, 48 + %tmp9 = inttoptr i64 %tmp8 to %class.F.3.111* + %tmp10 = add i64 %tmp5, 64 + %tmp11 = inttoptr i64 %tmp10 to %class.A.1.109* + %tmp12 = lshr i64 %tmp5, 3 + %tmp13 = add i64 %tmp12, 2147450880 + %tmp14 = add i64 %tmp13, 0 + %tmp15 = inttoptr i64 %tmp14 to i64* + store i64 -1008258751386226191, i64* %tmp15 + invoke void @_ZlsIiEv1CIT_Ej(i32 0) + to label %invoke.cont unwind label %lpad + +invoke.cont: ; preds = %bb4 + invoke void @_ZN18basic_stringstream5m_fn1Ev(%class.A.1.109* nonnull sret %tmp11, %class.basic_stringstream.2.110* nonnull %tmp7) + to label %invoke.cont2 unwind label %lpad + +invoke.cont2: ; preds = %invoke.cont + invoke void @_ZN1FC2E1A(%class.F.3.111* nonnull %tmp9, %class.A.1.109* nonnull %tmp11) + to label %try.cont unwind label %lpad3 + +lpad: ; preds = %invoke.cont, %bb4 + %tmp16 = landingpad { i8*, i32 } + cleanup + catch i8* bitcast (i8** @_ZTIi to i8*) + %tmp17 = extractvalue { i8*, i32 } %tmp16, 0 + br label %ehcleanup + +lpad3: ; preds = %invoke.cont2 + %tmp18 = landingpad { i8*, i32 } + cleanup + catch i8* bitcast (i8** @_ZTIi to i8*) + %tmp19 = extractvalue { i8*, i32 } %tmp18, 1 + br label %ehcleanup + +ehcleanup: ; preds = %lpad3, %lpad + %ehselector.slot.0 = phi i32 [ %tmp19, %lpad3 ], [ undef, %lpad ] + %exn.slot.0 = phi i8* [ undef, %lpad3 ], [ %tmp17, %lpad ] + call void @_ZN18basic_stringstreamD1Ev(%class.basic_stringstream.2.110* nonnull %tmp7) + %matches = icmp eq i32 %ehselector.slot.0, undef + br i1 %matches, label %catch, label %eh.resume + +catch: ; preds = %ehcleanup + %tmp20 = call i8* @__cxa_begin_catch(i8* %exn.slot.0) + br label %try.cont + +try.cont: ; preds = %catch, %invoke.cont2 + %tmp21 = icmp ne i64 %tmp2, 0 + br i1 %tmp21, label %bb22, label %bb25 + +bb22: ; preds = %try.cont + %tmp23 = add i64 %tmp13, 8 + %tmp24 = inttoptr i64 %tmp23 to i64* + store i64 -723401728380766731, i64* %tmp24 + br label %bb25 + +bb25: ; preds = %bb22, %try.cont + ret void + +eh.resume: ; preds = %ehcleanup + resume { i8*, i32 } undef +} + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.start(i64, i8* nocapture) + +declare void @_ZlsIiEv1CIT_Ej(i32) + +declare i32 @__gxx_personality_v0(...) + +declare void @_ZN18basic_stringstream5m_fn1Ev(%class.A.1.109* sret, %class.basic_stringstream.2.110*) + +declare void @_ZN1FC2E1A(%class.F.3.111*, %class.A.1.109* nocapture readnone) unnamed_addr align 2 + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.end(i64, i8* nocapture) + +declare void @_ZN18basic_stringstreamD1Ev(%class.basic_stringstream.2.110*) unnamed_addr + +; Function Attrs: nounwind readnone +declare i32 @llvm.eh.typeid.for(i8*) + +declare i8* @__cxa_begin_catch(i8*) + +declare void @__cxa_end_catch() + +declare i64 @__asan_stack_malloc_1(i64)