diff --git a/llvm/include/llvm/CodeGen/FastISel.h b/llvm/include/llvm/CodeGen/FastISel.h index 5cb7d8a6f40f..b9c1456c191e 100644 --- a/llvm/include/llvm/CodeGen/FastISel.h +++ b/llvm/include/llvm/CodeGen/FastISel.h @@ -381,6 +381,10 @@ private: /// hasTrivialKill - Test whether the given value has exactly one use. bool hasTrivialKill(const Value *V) const; + + /// removeDeadCode - Remove all dead instructions between the I and E. + void removeDeadCode(MachineBasicBlock::iterator I, + MachineBasicBlock::iterator E); }; } diff --git a/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp b/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp index 2087a1ba403e..b4946ec5ee84 100644 --- a/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp @@ -66,6 +66,7 @@ STATISTIC(NumFastIselSuccessIndependent, "Number of insts selected by " "target-independent selector"); STATISTIC(NumFastIselSuccessTarget, "Number of insts selected by " "target-specific selector"); +STATISTIC(NumFastIselDead, "Number of dead insts removed on failure"); /// startNewBlock - Set the current block to which generated machine /// instructions will be appended, and clear the local CSE map. @@ -309,6 +310,18 @@ void FastISel::recomputeInsertPt() { ++FuncInfo.InsertPt; } +void FastISel::removeDeadCode(MachineBasicBlock::iterator I, + MachineBasicBlock::iterator E) { + assert (I && E && std::distance(I, E) > 0 && "Invalid iterator!"); + while (I != E) { + MachineInstr *Dead = &*I; + ++I; + Dead->eraseFromParent(); + ++NumFastIselDead; + } + recomputeInsertPt(); +} + FastISel::SavePoint FastISel::enterLocalValueArea() { MachineBasicBlock::iterator OldInsertPt = FuncInfo.InsertPt; DebugLoc OldDL = DL; @@ -794,19 +807,33 @@ FastISel::SelectInstruction(const Instruction *I) { DL = I->getDebugLoc(); + MachineBasicBlock::iterator SavedInsertPt = FuncInfo.InsertPt; + // First, try doing target-independent selection. if (SelectOperator(I, I->getOpcode())) { ++NumFastIselSuccessIndependent; DL = DebugLoc(); return true; } + // Remove dead code. However, ignore call instructions since we've flushed + // the local value map and recomputed the insert point. + if (!isa(I)) { + recomputeInsertPt(); + if (SavedInsertPt != FuncInfo.InsertPt) + removeDeadCode(FuncInfo.InsertPt, SavedInsertPt); + } // Next, try calling the target to attempt to handle the instruction. + SavedInsertPt = FuncInfo.InsertPt; if (TargetSelectInstruction(I)) { ++NumFastIselSuccessTarget; DL = DebugLoc(); return true; } + // Check for dead code and remove as necessary. + recomputeInsertPt(); + if (SavedInsertPt != FuncInfo.InsertPt) + removeDeadCode(FuncInfo.InsertPt, SavedInsertPt); DL = DebugLoc(); return false; diff --git a/llvm/test/CodeGen/ARM/fast-isel-deadcode.ll b/llvm/test/CodeGen/ARM/fast-isel-deadcode.ll new file mode 100644 index 000000000000..028d94014fe3 --- /dev/null +++ b/llvm/test/CodeGen/ARM/fast-isel-deadcode.ll @@ -0,0 +1,23 @@ +; RUN: llc < %s -O0 -relocation-model=dynamic-no-pic -mtriple=thumbv7-apple-darwin | FileCheck %s --check-prefix=THUMB + +; Target-specific selector can't properly handle the double because it isn't +; being passed via a register, so the materialized arguments become dead code. + +define i32 @main(i32 %argc, i8** %argv) nounwind { +entry: +; THUMB: main + call void @printArgsNoRet(i32 1, float 0x4000CCCCC0000000, i8 signext 99, double 4.100000e+00) +; THUMB: blx _printArgsNoRet +; THUMB-NOT: ldr +; THUMB-NOT: vldr +; THUMB-NOT: vmov +; THUMB-NOT: ldr +; THUMB-NOT: sxtb +; THUMB: movs r0, #0 +; THUMB: movt r0, #0 +; THUMB: add sp, #32 +; THUMb: pop {r7, pc} + ret i32 0 +} + +declare void @printArgsNoRet(i32 %a1, float %a2, i8 signext %a3, double %a4)