mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-11-10 17:07:06 +00:00
6bbab86af9
dead code, including dead return instructions in some cases. Otherwise, we end up having a bogus poniter to a return instruction that blows up much further down the road. It turns out that this pattern is both simpler to code, easier to update in the face of enhancements to the inliner cleanup, and likely cheaper given that it won't add dead instructions to the list. Thanks to John Regehr's numerous test cases for teasing this out. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@154157 91177308-0d34-0410-b5e6-96231b3b80d8
176 lines
3.8 KiB
LLVM
176 lines
3.8 KiB
LLVM
; Test that the inliner doesn't leave around dead allocas, and that it folds
|
|
; uncond branches away after it is done specializing.
|
|
|
|
; RUN: opt < %s -inline -S | FileCheck %s
|
|
|
|
@A = weak global i32 0 ; <i32*> [#uses=1]
|
|
@B = weak global i32 0 ; <i32*> [#uses=1]
|
|
@C = weak global i32 0 ; <i32*> [#uses=1]
|
|
|
|
define internal fastcc void @foo(i32 %X) {
|
|
entry:
|
|
%ALL = alloca i32, align 4 ; <i32*> [#uses=1]
|
|
%tmp1 = and i32 %X, 1 ; <i32> [#uses=1]
|
|
%tmp1.upgrd.1 = icmp eq i32 %tmp1, 0 ; <i1> [#uses=1]
|
|
br i1 %tmp1.upgrd.1, label %cond_next, label %cond_true
|
|
|
|
cond_true: ; preds = %entry
|
|
store i32 1, i32* @A
|
|
br label %cond_next
|
|
|
|
cond_next: ; preds = %cond_true, %entry
|
|
%tmp4 = and i32 %X, 2 ; <i32> [#uses=1]
|
|
%tmp4.upgrd.2 = icmp eq i32 %tmp4, 0 ; <i1> [#uses=1]
|
|
br i1 %tmp4.upgrd.2, label %cond_next7, label %cond_true5
|
|
|
|
cond_true5: ; preds = %cond_next
|
|
store i32 1, i32* @B
|
|
br label %cond_next7
|
|
|
|
cond_next7: ; preds = %cond_true5, %cond_next
|
|
%tmp10 = and i32 %X, 4 ; <i32> [#uses=1]
|
|
%tmp10.upgrd.3 = icmp eq i32 %tmp10, 0 ; <i1> [#uses=1]
|
|
br i1 %tmp10.upgrd.3, label %cond_next13, label %cond_true11
|
|
|
|
cond_true11: ; preds = %cond_next7
|
|
store i32 1, i32* @C
|
|
br label %cond_next13
|
|
|
|
cond_next13: ; preds = %cond_true11, %cond_next7
|
|
%tmp16 = and i32 %X, 8 ; <i32> [#uses=1]
|
|
%tmp16.upgrd.4 = icmp eq i32 %tmp16, 0 ; <i1> [#uses=1]
|
|
br i1 %tmp16.upgrd.4, label %UnifiedReturnBlock, label %cond_true17
|
|
|
|
cond_true17: ; preds = %cond_next13
|
|
call void @ext( i32* %ALL )
|
|
ret void
|
|
|
|
UnifiedReturnBlock: ; preds = %cond_next13
|
|
ret void
|
|
}
|
|
|
|
declare void @ext(i32*)
|
|
|
|
define void @test() {
|
|
; CHECK: @test
|
|
; CHECK-NOT: ret
|
|
;
|
|
; FIXME: This should be a CHECK-NOT, but currently we have a bug that causes us
|
|
; to not nuke unused allocas.
|
|
; CHECK: alloca
|
|
; CHECK-NOT: ret
|
|
;
|
|
; No branches should survive the inliner's cleanup.
|
|
; CHECK-NOT: br
|
|
; CHECK: ret void
|
|
|
|
entry:
|
|
tail call fastcc void @foo( i32 1 )
|
|
tail call fastcc void @foo( i32 2 )
|
|
tail call fastcc void @foo( i32 3 )
|
|
tail call fastcc void @foo( i32 8 )
|
|
ret void
|
|
}
|
|
|
|
declare void @f(i32 %x)
|
|
|
|
define void @inner2(i32 %x, i32 %y, i32 %z, i1 %b) {
|
|
entry:
|
|
%cmp1 = icmp ne i32 %x, 0
|
|
br i1 %cmp1, label %then1, label %end1
|
|
|
|
then1:
|
|
call void @f(i32 %x)
|
|
br label %end1
|
|
|
|
end1:
|
|
%x2 = and i32 %x, %z
|
|
%cmp2 = icmp sgt i32 %x2, 1
|
|
br i1 %cmp2, label %then2, label %end2
|
|
|
|
then2:
|
|
call void @f(i32 %x2)
|
|
br label %end2
|
|
|
|
end2:
|
|
%y2 = or i32 %y, %z
|
|
%cmp3 = icmp sgt i32 %y2, 0
|
|
br i1 %cmp3, label %then3, label %end3
|
|
|
|
then3:
|
|
call void @f(i32 %y2)
|
|
br label %end3
|
|
|
|
end3:
|
|
br i1 %b, label %end3.1, label %end3.2
|
|
|
|
end3.1:
|
|
%x3.1 = or i32 %x, 10
|
|
br label %end3.3
|
|
|
|
end3.2:
|
|
%x3.2 = or i32 %x, 10
|
|
br label %end3.3
|
|
|
|
end3.3:
|
|
%x3.3 = phi i32 [ %x3.1, %end3.1 ], [ %x3.2, %end3.2 ]
|
|
%cmp4 = icmp slt i32 %x3.3, 1
|
|
br i1 %cmp4, label %then4, label %end4
|
|
|
|
then4:
|
|
call void @f(i32 %x3.3)
|
|
br label %end4
|
|
|
|
end4:
|
|
ret void
|
|
}
|
|
|
|
define void @outer2(i32 %z, i1 %b) {
|
|
; Ensure that after inlining, none of the blocks with a call to @f actually
|
|
; make it through inlining.
|
|
; CHECK: define void @outer2
|
|
; CHECK-NOT: call
|
|
; CHECK: ret void
|
|
|
|
entry:
|
|
call void @inner2(i32 0, i32 -1, i32 %z, i1 %b)
|
|
ret void
|
|
}
|
|
|
|
define void @PR12470_inner(i16 signext %p1) nounwind uwtable {
|
|
entry:
|
|
br i1 undef, label %cond.true, label %cond.false
|
|
|
|
cond.true:
|
|
br label %cond.end
|
|
|
|
cond.false:
|
|
%conv = sext i16 %p1 to i32
|
|
br label %cond.end
|
|
|
|
cond.end:
|
|
%cond = phi i32 [ undef, %cond.true ], [ 0, %cond.false ]
|
|
%tobool = icmp eq i32 %cond, 0
|
|
br i1 %tobool, label %if.end5, label %if.then
|
|
|
|
if.then:
|
|
ret void
|
|
|
|
if.end5:
|
|
ret void
|
|
}
|
|
|
|
define void @PR12470_outer() {
|
|
; This previously crashed during inliner cleanup and folding inner return
|
|
; instructions. Check that we don't crash and we produce a function with a single
|
|
; crash.
|
|
; CHECK: define void @PR12470_outer
|
|
; CHECK: ret void
|
|
; CHECK-NOT: ret void
|
|
; CHECK: }
|
|
|
|
entry:
|
|
call void @PR12470_inner(i16 signext 1)
|
|
ret void
|
|
}
|