mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-02-01 05:01:59 +01:00
f7c5e4104c
For basic blocks with instructions between the beginning of the block and a call we have to duplicate the instructions before the call in all split blocks and add PHI nodes for uses of the duplicated instructions after the call. Currently, the threshold for the number of instructions before a call is quite low, to keep the impact on binary size low. Reviewers: junbuml, mcrosier, davidxl, davide Reviewed By: junbuml Differential Revision: https://reviews.llvm.org/D41860 llvm-svn: 325001
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
|
|
}
|