254 lines
8.2 KiB
LLVM
254 lines
8.2 KiB
LLVM
|
; RUN: opt -S -callsite-splitting < %s | FileCheck --check-prefix=CHECK %s
|
||
|
; RUN: opt -S -callsite-splitting -callsite-splitting-duplication-threshold=0 < %s | FileCheck --check-prefix=NODUP %s
|
||
|
|
||
|
; Instructions before a call that will be pushed to its predecessors
|
||
|
; with uses after the callsite, must be patched up as PHI nodes in
|
||
|
; the join block.
|
||
|
define i32* @test_split_branch_phi(i32* %ptrarg, i32 %i) {
|
||
|
Header:
|
||
|
%tobool = icmp ne i32* %ptrarg, null
|
||
|
br i1 %tobool, label %TBB, label %CallSite
|
||
|
|
||
|
TBB: ; preds = %Header
|
||
|
%arrayidx = getelementptr inbounds i32, i32* %ptrarg, i64 42
|
||
|
%0 = load i32, i32* %arrayidx, align 4
|
||
|
%tobool1 = icmp ne i32 %0, 0
|
||
|
br i1 %tobool1, label %CallSite, label %End
|
||
|
|
||
|
CallSite: ; preds = %TBB, %Header
|
||
|
%somepointer = getelementptr i32, i32* %ptrarg, i64 18
|
||
|
call void @bar(i32* %ptrarg, i32 %i)
|
||
|
br label %End
|
||
|
|
||
|
End: ; preds = %CallSite, %TBB
|
||
|
%somepointerphi = phi i32* [ %somepointer, %CallSite ], [ null, %TBB ]
|
||
|
ret i32* %somepointerphi
|
||
|
}
|
||
|
; NODUP-LABEL: test_split_branch_phi
|
||
|
; NODUP-NOT: split
|
||
|
; CHECK-LABEL: Header.split
|
||
|
; CHECK: %[[V1:somepointer[0-9]+]] = getelementptr i32, i32* %ptrarg, i64 18
|
||
|
; CHECK: call void @bar(i32* null, i32 %i)
|
||
|
; CHECK: br label %CallSite
|
||
|
; CHECK-LABEL: TBB.split:
|
||
|
; CHECK: %[[V2:somepointer[0-9]+]] = getelementptr i32, i32* %ptrarg, i64 18
|
||
|
; CHECK: call void @bar(i32* nonnull %ptrarg, i32 %i)
|
||
|
; CHECK: br label %CallSite
|
||
|
; CHECK: CallSite:
|
||
|
; CHECK: phi i32* [ %[[V1]], %Header.split ], [ %[[V2]], %TBB.split ]
|
||
|
|
||
|
|
||
|
define void @split_branch_no_extra_phi(i32* %ptrarg, i32 %i) {
|
||
|
Header:
|
||
|
%tobool = icmp ne i32* %ptrarg, null
|
||
|
br i1 %tobool, label %TBB, label %CallSite
|
||
|
|
||
|
TBB: ; preds = %Header
|
||
|
%arrayidx = getelementptr inbounds i32, i32* %ptrarg, i64 42
|
||
|
%0 = load i32, i32* %arrayidx, align 4
|
||
|
%tobool1 = icmp ne i32 %0, 0
|
||
|
br i1 %tobool1, label %CallSite, label %End
|
||
|
|
||
|
CallSite: ; preds = %TBB, %Header
|
||
|
%i.add = add i32 %i, 99
|
||
|
call void @bar(i32* %ptrarg, i32 %i.add)
|
||
|
br label %End
|
||
|
|
||
|
End: ; preds = %CallSite, %TBB
|
||
|
ret void
|
||
|
}
|
||
|
; NODUP-LABEL: split_branch_no_extra_phi
|
||
|
; NODUP-NOT: split
|
||
|
; CHECK-LABEL: split_branch_no_extra_phi
|
||
|
; CHECK-LABEL: Header.split
|
||
|
; CHECK: %[[V1:.+]] = add i32 %i, 99
|
||
|
; CHECK: call void @bar(i32* null, i32 %[[V1]])
|
||
|
; CHECK: br label %CallSite
|
||
|
; CHECK-LABEL: TBB.split:
|
||
|
; CHECK: %[[V2:.+]] = add i32 %i, 99
|
||
|
; CHECK: call void @bar(i32* nonnull %ptrarg, i32 %[[V2]])
|
||
|
; CHECK: br label %CallSite
|
||
|
; CHECK: CallSite:
|
||
|
; CHECK-NOT: phi
|
||
|
|
||
|
|
||
|
; In this test case, the codesize cost of the instructions before the call to
|
||
|
; bar() is equal to the default DuplicationThreshold of 5, because calls are
|
||
|
; more expensive.
|
||
|
define void @test_no_split_threshold(i32* %ptrarg, i32 %i) {
|
||
|
Header:
|
||
|
%tobool = icmp ne i32* %ptrarg, null
|
||
|
br i1 %tobool, label %TBB, label %CallSite
|
||
|
|
||
|
TBB: ; preds = %Header
|
||
|
%arrayidx = getelementptr inbounds i32, i32* %ptrarg, i64 42
|
||
|
%0 = load i32, i32* %arrayidx, align 4
|
||
|
%tobool1 = icmp ne i32 %0, 0
|
||
|
br i1 %tobool1, label %CallSite, label %End
|
||
|
|
||
|
CallSite: ; preds = %TBB, %Header
|
||
|
%i2 = add i32 %i, 10
|
||
|
call void @bari(i32 %i2)
|
||
|
call void @bari(i32 %i2)
|
||
|
call void @bar(i32* %ptrarg, i32 %i2)
|
||
|
br label %End
|
||
|
|
||
|
End: ; preds = %CallSite, %TBB
|
||
|
ret void
|
||
|
}
|
||
|
; NODUP-LABEL: test_no_split_threshold
|
||
|
; NODUP-NOT: split
|
||
|
; CHECK-LABEL: test_no_split_threshold
|
||
|
; CHECK-NOT: split
|
||
|
; CHECK-LABEL: CallSite:
|
||
|
; CHECK: call void @bar(i32* %ptrarg, i32 %i2)
|
||
|
|
||
|
; In this test case, the phi node %l in CallSite should be removed, as after
|
||
|
; moving the call to the split blocks we can use the values directly.
|
||
|
define void @test_remove_unused_phi(i32* %ptrarg, i32 %i) {
|
||
|
Header:
|
||
|
%l1 = load i32, i32* undef, align 16
|
||
|
%tobool = icmp ne i32* %ptrarg, null
|
||
|
br i1 %tobool, label %TBB, label %CallSite
|
||
|
|
||
|
TBB: ; preds = %Header
|
||
|
%arrayidx = getelementptr inbounds i32, i32* %ptrarg, i64 42
|
||
|
%0 = load i32, i32* %arrayidx, align 4
|
||
|
%l2 = load i32, i32* undef, align 16
|
||
|
%tobool1 = icmp ne i32 %0, 0
|
||
|
br i1 %tobool1, label %CallSite, label %End
|
||
|
|
||
|
CallSite: ; preds = %TBB, %Header
|
||
|
%l = phi i32 [ %l1, %Header ], [ %l2, %TBB ]
|
||
|
call void @bar(i32* %ptrarg, i32 %l)
|
||
|
br label %End
|
||
|
|
||
|
End: ; preds = %CallSite, %TBB
|
||
|
ret void
|
||
|
}
|
||
|
; NODUP-LABEL: test_remove_unused_phi
|
||
|
; NODUP-NOT: split
|
||
|
; CHECK-LABEL: test_remove_unused_phi
|
||
|
; CHECK-LABEL: Header.split
|
||
|
; CHECK: call void @bar(i32* null, i32 %l1)
|
||
|
; CHECK: br label %CallSite
|
||
|
; CHECK-LABEL: TBB.split:
|
||
|
; CHECK: call void @bar(i32* nonnull %ptrarg, i32 %l2)
|
||
|
; CHECK: br label %CallSite
|
||
|
; CHECK-LABEL: CallSite:
|
||
|
; CHECK-NOT: phi
|
||
|
|
||
|
; In this test case, we need to insert a new PHI node in TailBB to combine
|
||
|
; the loads we moved to the predecessors.
|
||
|
define void @test_add_new_phi(i32* %ptrarg, i32 %i) {
|
||
|
Header:
|
||
|
%tobool = icmp ne i32* %ptrarg, null
|
||
|
br i1 %tobool, label %TBB, label %CallSite
|
||
|
|
||
|
TBB:
|
||
|
br i1 undef, label %CallSite, label %End
|
||
|
|
||
|
CallSite:
|
||
|
%arrayidx112 = getelementptr inbounds i32, i32* undef, i64 1
|
||
|
%0 = load i32, i32* %arrayidx112, align 4
|
||
|
call void @bar(i32* %ptrarg, i32 %i)
|
||
|
%sub = sub nsw i32 %0, undef
|
||
|
br label %End
|
||
|
|
||
|
End: ; preds = %CallSite, %TBB
|
||
|
ret void
|
||
|
}
|
||
|
; NODUP-LABEL: test_add_new_phi
|
||
|
; NODUP-NOT: split
|
||
|
; CHECK-LABEL: test_add_new_phi
|
||
|
; CHECK-LABEL: Header.split
|
||
|
; CHECK: %[[V1:.+]] = load i32, i32*
|
||
|
; CHECK: call void @bar(i32* null, i32 %i)
|
||
|
; CHECK: br label %CallSite
|
||
|
; CHECK-LABEL: TBB.split:
|
||
|
; CHECK: %[[V2:.+]] = load i32, i32*
|
||
|
; CHECK: call void @bar(i32* nonnull %ptrarg, i32 %i)
|
||
|
; CHECK: br label %CallSite
|
||
|
; CHECK-LABEL: CallSite:
|
||
|
; CHECK-NEXT: %[[V3:.+]] = phi i32 [ %[[V1]], %Header.split ], [ %[[V2]], %TBB.split ]
|
||
|
; CHECK: %sub = sub nsw i32 %[[V3]], undef
|
||
|
|
||
|
define i32 @test_firstnophi(i32* %a, i32 %v) {
|
||
|
Header:
|
||
|
%tobool1 = icmp eq i32* %a, null
|
||
|
br i1 %tobool1, label %Tail, label %TBB
|
||
|
|
||
|
TBB:
|
||
|
%cmp = icmp eq i32 %v, 1
|
||
|
br i1 %cmp, label %Tail, label %End
|
||
|
|
||
|
Tail:
|
||
|
%p = phi i32[1,%Header], [2, %TBB]
|
||
|
store i32 %v, i32* %a
|
||
|
%r = call i32 @callee(i32* %a, i32 %v, i32 %p)
|
||
|
ret i32 %r
|
||
|
|
||
|
End:
|
||
|
ret i32 %v
|
||
|
}
|
||
|
; NODUP-LABEL: @test_firstnophi
|
||
|
; NODUP-NOT: split:
|
||
|
; CHECK-LABEL: @test_firstnophi
|
||
|
; CHECK-LABEL: Header.split:
|
||
|
; CHECK-NEXT: store i32 %v, i32* %a
|
||
|
; CHECK-NEXT: %[[CALL1:.*]] = call i32 @callee(i32* null, i32 %v, i32 1)
|
||
|
; CHECK-NEXT: br label %Tail
|
||
|
; CHECK-LABEL: TBB.split:
|
||
|
; CHECK-NEXT: store i32 %v, i32* %a
|
||
|
; CHECK-NEXT: %[[CALL2:.*]] = call i32 @callee(i32* nonnull %a, i32 1, i32 2)
|
||
|
; CHECK-NEXT: br label %Tail
|
||
|
; CHECK-LABEL: Tail:
|
||
|
; CHECK: %[[MERGED:.*]] = phi i32 [ %[[CALL1]], %Header.split ], [ %[[CALL2]], %TBB.split ]
|
||
|
; CHECK: ret i32 %[[MERGED]]
|
||
|
define i32 @callee(i32* %a, i32 %v, i32 %p) {
|
||
|
ret i32 0
|
||
|
}
|
||
|
|
||
|
define void @test_no_remove_used_phi(i32* %ptrarg, i32 %i) {
|
||
|
Header:
|
||
|
%l1 = load i32, i32* undef, align 16
|
||
|
%tobool = icmp ne i32* %ptrarg, null
|
||
|
br i1 %tobool, label %TBB, label %CallSite
|
||
|
|
||
|
TBB: ; preds = %Header
|
||
|
%arrayidx = getelementptr inbounds i32, i32* %ptrarg, i64 42
|
||
|
%0 = load i32, i32* %arrayidx, align 4
|
||
|
%l2 = load i32, i32* undef, align 16
|
||
|
%tobool1 = icmp ne i32 %0, 0
|
||
|
br i1 %tobool1, label %CallSite, label %End
|
||
|
|
||
|
CallSite: ; preds = %TBB, %Header
|
||
|
%l = phi i32 [ %l1, %Header ], [ %l2, %TBB ]
|
||
|
call void @bar(i32* %ptrarg, i32 %l)
|
||
|
call void @bari(i32 %l)
|
||
|
br label %End
|
||
|
|
||
|
End: ; preds = %CallSite, %TBB
|
||
|
ret void
|
||
|
}
|
||
|
; NODUP-LABEL: @test_no_remove_used_phi
|
||
|
; NODUP-NOT: split
|
||
|
; CHECK-LABEL: @test_no_remove_used_phi
|
||
|
; CHECK-LABEL: Header.split:
|
||
|
; CHECK: call void @bar(i32* null, i32 %l1)
|
||
|
; CHECK-NEXT: br label %CallSite
|
||
|
; CHECK-LABEL: TBB.split:
|
||
|
; CHECK: call void @bar(i32* nonnull %ptrarg, i32 %l2)
|
||
|
; CHECK-NEXT: br label %CallSite
|
||
|
; CHECK-LABEL: CallSite:
|
||
|
; CHECK-NEXT: %l = phi i32 [ %l1, %Header.split ], [ %l2, %TBB.split ]
|
||
|
; CHECK: call void @bari(i32 %l)
|
||
|
|
||
|
define void @bar(i32*, i32) {
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
define void @bari(i32) {
|
||
|
ret void
|
||
|
}
|