Index: llvm/trunk/lib/Transforms/IPO/Attributor.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/Attributor.cpp +++ llvm/trunk/lib/Transforms/IPO/Attributor.cpp @@ -1868,7 +1868,7 @@ Function &F = *getAssociatedFunction(); if (AssumedLiveBlocks.empty()) { - F.replaceAllUsesWith(UndefValue::get(F.getType())); + A.deleteAfterManifest(F); return ChangeStatus::CHANGED; } @@ -1918,6 +1918,9 @@ } } } + + if (SplitPos == &NormalDestBB->front()) + AssumedLiveBlocks.insert(NormalDestBB); } BB = SplitPos->getParent(); @@ -1926,6 +1929,10 @@ HasChanged = ChangeStatus::CHANGED; } + for (BasicBlock &BB : F) + if (!AssumedLiveBlocks.count(&BB)) + A.deleteAfterManifest(BB); + return HasChanged; } @@ -3309,14 +3316,18 @@ << " blocks and " << ToBeDeletedInsts.size() << " instructions\n"); for (Instruction *I : ToBeDeletedInsts) { - if (I->hasNUsesOrMore(1)) + if (!I->use_empty()) I->replaceAllUsesWith(UndefValue::get(I->getType())); I->eraseFromParent(); } - for (BasicBlock *BB : ToBeDeletedBlocks) { - // TODO: Check if we need to replace users (PHIs, indirect branches?) - BB->eraseFromParent(); + + if (unsigned NumDeadBlocks = ToBeDeletedBlocks.size()) { + SmallVector ToBeDeletedBBs; + ToBeDeletedBBs.reserve(NumDeadBlocks); + ToBeDeletedBBs.append(ToBeDeletedBlocks.begin(), ToBeDeletedBlocks.end()); + DeleteDeadBlocks(ToBeDeletedBBs); } + for (Function *Fn : ToBeDeletedFunctions) { Fn->replaceAllUsesWith(UndefValue::get(Fn->getType())); Fn->eraseFromParent(); Index: llvm/trunk/test/Transforms/FunctionAttrs/arg_returned.ll =================================================================== --- llvm/trunk/test/Transforms/FunctionAttrs/arg_returned.ll +++ llvm/trunk/test/Transforms/FunctionAttrs/arg_returned.ll @@ -804,10 +804,8 @@ ; BOTH-DAG: attributes #{{[0-9]*}} = { nofree noinline nosync nounwind readnone uwtable } ; BOTH-DAG: attributes #{{[0-9]*}} = { nofree noinline noreturn nosync nounwind readonly uwtable } ; BOTH-DAG: attributes #{{[0-9]*}} = { noinline nounwind uwtable } -; BOTH-DAG: attributes #{{[0-9]*}} = { nofree noinline nosync nounwind readnone uwtable willreturn } -; BOTH-DAG: attributes #{{[0-9]*}} = { nofree noinline nosync nounwind uwtable willreturn } +; BOTH-DAG: attributes #{{[0-9]*}} = { noreturn } ; BOTH-DAG: attributes #{{[0-9]*}} = { nofree nosync willreturn } ; BOTH-DAG: attributes #{{[0-9]*}} = { nofree nosync } ; BOTH-DAG: attributes #{{[0-9]*}} = { nofree noreturn nosync } -; BOTH-DAG: attributes #{{[0-9]*}} = { noreturn } ; BOTH-NOT: attributes # Index: llvm/trunk/test/Transforms/FunctionAttrs/liveness.ll =================================================================== --- llvm/trunk/test/Transforms/FunctionAttrs/liveness.ll +++ llvm/trunk/test/Transforms/FunctionAttrs/liveness.ll @@ -15,7 +15,7 @@ ; This internal function has no live call sites, so all its BBs are considered dead, ; and nothing should be deduced for it. -; CHECK: define internal i32 @dead_internal_func(i32 %0) +; CHECK-NOT: define internal i32 @dead_internal_func(i32 %0) define internal i32 @dead_internal_func(i32 %0) { %2 = icmp slt i32 %0, 1 br i1 %2, label %3, label %5 @@ -56,14 +56,13 @@ call void @no_return_call() ; CHECK: call void @no_return_call() ; CHECK-NEXT: unreachable + ; CHECK-NEXT: } call i32 @dead_internal_func(i32 10) - ; CHECK call i32 undef(i32 10) %cmp = icmp eq i32 %a, 0 br i1 %cmp, label %cond.true, label %cond.false cond.true: ; preds = %entry call i32 @internal_load(i32* %ptr2) - ; CHECK: call i32 @internal_load(i32* %ptr2) %load = call i32 @volatile_load(i32* %ptr1) call void @normal_call() %call = call i32 @foo() @@ -104,6 +103,8 @@ br label %cond.end cond.end: ; preds = %cond.false, %cond.true +; CHECK: cond.end: +; CHECK-NEXT: ret i32 %call1 %cond = phi i32 [ %call, %cond.true ], [ %call1, %cond.false ] ret i32 %cond } @@ -120,7 +121,7 @@ ; CHECK: call void @no_return_call() ; CHECK-NEXT: unreachable call i32 @dead_internal_func(i32 10) - ; CHECK call i32 undef(i32 10) + ; CHECK-NOT: call %call = call i32 @foo() br label %cond.end @@ -129,7 +130,7 @@ ; CHECK: call void @no_return_call() ; CHECK-NEXT: unreachable call i32 @dead_internal_func(i32 10) - ; CHECK call i32 undef(i32 10) + ; CHECK-NEXT: } %call1 = call i32 @bar() br label %cond.end @@ -215,9 +216,7 @@ ; CHECK-NEXT: call i32 @foo_noreturn_nounwind() ; CHECK-NEXT: unreachable - ; We keep the invoke around as other attributes might have references to it. - ; CHECK: cond.true.split: ; No predecessors! - ; CHECK-NEXT: invoke i32 @foo_noreturn_nounwind() + ; CHECK-NOT: @foo_noreturn_nounwind() cond.false: ; preds = %entry call void @normal_call()