This recommit r317351 after fixing a buildbot failure.
Original commit message:
Summary:
This change add a pass which tries to split a call-site to pass
more constrained arguments if its argument is predicated in the control flow
so that we can expose better context to the later passes (e.g, inliner, jump
threading, or IPA-CP based function cloning, etc.).
As of now we support two cases :
1) If a call site is dominated by an OR condition and if any of its arguments
are predicated on this OR condition, try to split the condition with more
constrained arguments. For example, in the code below, we try to split the
call site since we can predicate the argument (ptr) based on the OR condition.
Split from :
if (!ptr || c)
callee(ptr);
to :
if (!ptr)
callee(null ptr) // set the known constant value
else if (c)
callee(nonnull ptr) // set non-null attribute in the argument
2) We can also split a call-site based on constant incoming values of a PHI
For example,
from :
BB0:
%c = icmp eq i32 %i1, %i2
br i1 %c, label %BB2, label %BB1
BB1:
br label %BB2
BB2:
%p = phi i32 [ 0, %BB0 ], [ 1, %BB1 ]
call void @bar(i32 %p)
to
BB0:
%c = icmp eq i32 %i1, %i2
br i1 %c, label %BB2-split0, label %BB1
BB1:
br label %BB2-split1
BB2-split0:
call void @bar(i32 0)
br label %BB2
BB2-split1:
call void @bar(i32 1)
br label %BB2
BB2:
%p = phi i32 [ 0, %BB2-split0 ], [ 1, %BB2-split1 ]
llvm-svn: 317362
340 lines
9.2 KiB
LLVM
340 lines
9.2 KiB
LLVM
; RUN: opt < %s -callsite-splitting -S | FileCheck %s
|
|
; RUN: opt < %s -passes='function(callsite-splitting)' -S | FileCheck %s
|
|
|
|
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
|
|
target triple = "aarch64-linaro-linux-gnueabi"
|
|
|
|
;CHECK-LABEL: @test_eq_eq
|
|
;CHECK-LABEL: Tail.predBB1.split:
|
|
;CHECK: %[[CALL1:.*]] = call i32 @callee(i32* null, i32 %v, i32 1)
|
|
;CHECK-LABEL: Tail.predBB2.split:
|
|
;CHECK: %[[CALL2:.*]] = call i32 @callee(i32* nonnull %a, i32 1, i32 2)
|
|
;CHECK-LABEL: Tail
|
|
;CHECK: %p = phi i32 [ 1, %Tail.predBB1.split ], [ 2, %Tail.predBB2.split ]
|
|
;CHECK: %[[MERGED:.*]] = phi i32 [ %[[CALL1]], %Tail.predBB1.split ], [ %[[CALL2]], %Tail.predBB2.split ]
|
|
;CHECK: ret i32 %[[MERGED]]
|
|
define i32 @test_eq_eq(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]
|
|
%r = call i32 @callee(i32* %a, i32 %v, i32 %p)
|
|
ret i32 %r
|
|
|
|
End:
|
|
ret i32 %v
|
|
}
|
|
|
|
;CHECK-LABEL: @test_ne_eq
|
|
;CHECK-LABEL: Tail.predBB1.split:
|
|
;CHECK: %[[CALL1:.*]] = call i32 @callee(i32* nonnull %a, i32 %v, i32 1)
|
|
;CHECK-LABEL: Tail.predBB2.split:
|
|
;CHECK: %[[CALL2:.*]] = call i32 @callee(i32* null, i32 1, i32 2)
|
|
;CHECK-LABEL: Tail
|
|
;CHECK: %p = phi i32 [ 1, %Tail.predBB1.split ], [ 2, %Tail.predBB2.split ]
|
|
;CHECK: %[[MERGED:.*]] = phi i32 [ %[[CALL1]], %Tail.predBB1.split ], [ %[[CALL2]], %Tail.predBB2.split ]
|
|
;CHECK: ret i32 %[[MERGED]]
|
|
define i32 @test_ne_eq(i32* %a, i32 %v) {
|
|
Header:
|
|
%tobool1 = icmp ne 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]
|
|
%r = call i32 @callee(i32* %a, i32 %v, i32 %p)
|
|
ret i32 %r
|
|
|
|
End:
|
|
ret i32 %v
|
|
}
|
|
|
|
;CHECK-LABEL: @test_ne_ne
|
|
;CHECK-LABEL: Tail.predBB1.split:
|
|
;CHECK: %[[CALL1:.*]] = call i32 @callee(i32* nonnull %a, i32 %v, i32 1)
|
|
;CHECK-LABEL: Tail.predBB2.split:
|
|
;CHECK: %[[CALL2:.*]] = call i32 @callee(i32* null, i32 %v, i32 2)
|
|
;CHECK-LABEL: Tail
|
|
;CHECK: %p = phi i32 [ 1, %Tail.predBB1.split ], [ 2, %Tail.predBB2.split ]
|
|
;CHECK: %[[MERGED:.*]] = phi i32 [ %[[CALL1]], %Tail.predBB1.split ], [ %[[CALL2]], %Tail.predBB2.split ]
|
|
;CHECK: ret i32 %[[MERGED]]
|
|
define i32 @test_ne_ne(i32* %a, i32 %v) {
|
|
Header:
|
|
%tobool1 = icmp ne i32* %a, null
|
|
br i1 %tobool1, label %Tail, label %TBB
|
|
|
|
TBB:
|
|
%cmp = icmp ne i32 %v, 1
|
|
br i1 %cmp, label %Tail, label %End
|
|
|
|
Tail:
|
|
%p = phi i32[1,%Header], [2, %TBB]
|
|
%r = call i32 @callee(i32* %a, i32 %v, i32 %p)
|
|
ret i32 %r
|
|
|
|
End:
|
|
ret i32 %v
|
|
}
|
|
|
|
;CHECK-LABEL: @test_eq_eq_untaken
|
|
;CHECK-LABEL: Tail.predBB1.split:
|
|
;CHECK: %[[CALL1:.*]] = call i32 @callee(i32* nonnull %a, i32 %v, i32 1)
|
|
;CHECK-LABEL: Tail.predBB2.split:
|
|
;CHECK: %[[CALL2:.*]] = call i32 @callee(i32* null, i32 1, i32 2)
|
|
;CHECK-LABEL: Tail
|
|
;CHECK: %p = phi i32 [ 1, %Tail.predBB1.split ], [ 2, %Tail.predBB2.split ]
|
|
;CHECK: %[[MERGED:.*]] = phi i32 [ %[[CALL1]], %Tail.predBB1.split ], [ %[[CALL2]], %Tail.predBB2.split ]
|
|
;CHECK: ret i32 %[[MERGED]]
|
|
define i32 @test_eq_eq_untaken(i32* %a, i32 %v) {
|
|
Header:
|
|
%tobool1 = icmp eq i32* %a, null
|
|
br i1 %tobool1, label %TBB, label %Tail
|
|
|
|
TBB:
|
|
%cmp = icmp eq i32 %v, 1
|
|
br i1 %cmp, label %Tail, label %End
|
|
|
|
Tail:
|
|
%p = phi i32[1,%Header], [2, %TBB]
|
|
%r = call i32 @callee(i32* %a, i32 %v, i32 %p)
|
|
ret i32 %r
|
|
|
|
End:
|
|
ret i32 %v
|
|
}
|
|
|
|
;CHECK-LABEL: @test_ne_eq_untaken
|
|
;CHECK-LABEL: Tail.predBB1.split:
|
|
;CHECK: %[[CALL1:.*]] = call i32 @callee(i32* null, i32 %v, i32 1)
|
|
;CHECK-LABEL: Tail.predBB2.split:
|
|
;CHECK: %[[CALL2:.*]] = call i32 @callee(i32* nonnull %a, i32 1, i32 2)
|
|
;CHECK-LABEL: Tail
|
|
;CHECK: %p = phi i32 [ 1, %Tail.predBB1.split ], [ 2, %Tail.predBB2.split ]
|
|
;CHECK: %[[MERGED:.*]] = phi i32 [ %[[CALL1]], %Tail.predBB1.split ], [ %[[CALL2]], %Tail.predBB2.split ]
|
|
;CHECK: ret i32 %[[MERGED]]
|
|
define i32 @test_ne_eq_untaken(i32* %a, i32 %v) {
|
|
Header:
|
|
%tobool1 = icmp ne i32* %a, null
|
|
br i1 %tobool1, label %TBB, label %Tail
|
|
|
|
TBB:
|
|
%cmp = icmp eq i32 %v, 1
|
|
br i1 %cmp, label %Tail, label %End
|
|
|
|
Tail:
|
|
%p = phi i32[1,%Header], [2, %TBB]
|
|
%r = call i32 @callee(i32* %a, i32 %v, i32 %p)
|
|
ret i32 %r
|
|
|
|
End:
|
|
ret i32 %v
|
|
}
|
|
|
|
;CHECK-LABEL: @test_ne_ne_untaken
|
|
;CHECK-LABEL: Tail.predBB1.split:
|
|
;CHECK: %[[CALL1:.*]] = call i32 @callee(i32* null, i32 %v, i32 1)
|
|
;CHECK-LABEL: Tail.predBB2.split:
|
|
;CHECK: %[[CALL2:.*]] = call i32 @callee(i32* nonnull %a, i32 1, i32 2)
|
|
;CHECK-LABEL: Tail
|
|
;CHECK: %p = phi i32 [ 1, %Tail.predBB1.split ], [ 2, %Tail.predBB2.split ]
|
|
;CHECK: %[[MERGED:.*]] = phi i32 [ %[[CALL1]], %Tail.predBB1.split ], [ %[[CALL2]], %Tail.predBB2.split ]
|
|
;CHECK: ret i32 %[[MERGED]]
|
|
define i32 @test_ne_ne_untaken(i32* %a, i32 %v) {
|
|
Header:
|
|
%tobool1 = icmp ne i32* %a, null
|
|
br i1 %tobool1, label %TBB, label %Tail
|
|
|
|
TBB:
|
|
%cmp = icmp ne i32 %v, 1
|
|
br i1 %cmp, label %End, label %Tail
|
|
|
|
Tail:
|
|
%p = phi i32[1,%Header], [2, %TBB]
|
|
%r = call i32 @callee(i32* %a, i32 %v, i32 %p)
|
|
ret i32 %r
|
|
|
|
End:
|
|
ret i32 %v
|
|
}
|
|
|
|
;CHECK-LABEL: @test_nonconst_const_phi
|
|
;CHECK-LABEL: Tail.predBB1.split:
|
|
;CHECK: %[[CALL1:.*]] = call i32 @callee(i32* %a, i32 %v, i32 1)
|
|
;CHECK-LABEL: Tail.predBB2.split:
|
|
;CHECK: %[[CALL2:.*]] = call i32 @callee(i32* %a, i32 1, i32 2)
|
|
;CHECK-LABEL: Tail
|
|
;CHECK: %p = phi i32 [ 1, %Tail.predBB1.split ], [ 2, %Tail.predBB2.split ]
|
|
;CHECK: %[[MERGED:.*]] = phi i32 [ %[[CALL1]], %Tail.predBB1.split ], [ %[[CALL2]], %Tail.predBB2.split ]
|
|
;CHECK: ret i32 %[[MERGED]]
|
|
define i32 @test_nonconst_const_phi(i32* %a, i32* %b, i32 %v) {
|
|
Header:
|
|
%tobool1 = icmp eq i32* %a, %b
|
|
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]
|
|
%r = call i32 @callee(i32* %a, i32 %v, i32 %p)
|
|
ret i32 %r
|
|
|
|
End:
|
|
ret i32 %v
|
|
}
|
|
|
|
;CHECK-LABEL: @test_nonconst_nonconst_phi
|
|
;CHECK-LABEL: Tail.predBB1.split:
|
|
;CHECK: %[[CALL1:.*]] = call i32 @callee(i32* %a, i32 %v, i32 1)
|
|
;CHECK-LABEL: Tail.predBB2.split:
|
|
;CHECK: %[[CALL2:.*]] = call i32 @callee(i32* %a, i32 %v, i32 2)
|
|
;CHECK-LABEL: Tail
|
|
;CHECK: %p = phi i32 [ 1, %Tail.predBB1.split ], [ 2, %Tail.predBB2.split ]
|
|
;CHECK: %[[MERGED:.*]] = phi i32 [ %[[CALL1]], %Tail.predBB1.split ], [ %[[CALL2]], %Tail.predBB2.split ]
|
|
;CHECK: ret i32 %[[MERGED]]
|
|
define i32 @test_nonconst_nonconst_phi(i32* %a, i32* %b, i32 %v, i32 %v2) {
|
|
Header:
|
|
%tobool1 = icmp eq i32* %a, %b
|
|
br i1 %tobool1, label %Tail, label %TBB
|
|
|
|
TBB:
|
|
%cmp = icmp eq i32 %v, %v2
|
|
br i1 %cmp, label %Tail, label %End
|
|
|
|
Tail:
|
|
%p = phi i32[1,%Header], [2, %TBB]
|
|
%r = call i32 @callee(i32* %a, i32 %v, i32 %p)
|
|
ret i32 %r
|
|
|
|
End:
|
|
ret i32 %v
|
|
}
|
|
|
|
;CHECK-LABEL: @test_nonconst_nonconst_phi_noncost
|
|
;CHECK-NOT: Tail.predBB1.split:
|
|
;CHECK-NOT: Tail.predBB2.split:
|
|
;CHECK-LABEL: Tail:
|
|
;CHECK: %r = call i32 @callee(i32* %a, i32 %v, i32 %p)
|
|
;CHECK: ret i32 %r
|
|
define i32 @test_nonconst_nonconst_phi_noncost(i32* %a, i32* %b, i32 %v, i32 %v2) {
|
|
Header:
|
|
%tobool1 = icmp eq i32* %a, %b
|
|
br i1 %tobool1, label %Tail, label %TBB
|
|
|
|
TBB:
|
|
%cmp = icmp eq i32 %v, %v2
|
|
br i1 %cmp, label %Tail, label %End
|
|
|
|
Tail:
|
|
%p = phi i32[%v,%Header], [%v2, %TBB]
|
|
%r = call i32 @callee(i32* %a, i32 %v, i32 %p)
|
|
ret i32 %r
|
|
|
|
End:
|
|
ret i32 %v
|
|
}
|
|
|
|
;CHECK-LABEL: @test_fisrtnonphi
|
|
;CHECK-NOT: Tail.predBB1.split:
|
|
;CHECK-NOT: Tail.predBB2.split:
|
|
;CHECK-LABEL: Tail:
|
|
;CHECK: %r = call i32 @callee(i32* %a, i32 %v, i32 %p)
|
|
;CHECK: ret i32 %r
|
|
define i32 @test_fisrtnonphi(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
|
|
}
|
|
|
|
;CHECK-LABEL: @test_3preds_constphi
|
|
;CHECK-NOT: Tail.predBB1.split:
|
|
;CHECK-NOT: Tail.predBB2.split:
|
|
;CHECK-LABEL: Tail:
|
|
;CHECK: %r = call i32 @callee(i32* %a, i32 %v, i32 %p)
|
|
;CHECK: ret i32 %r
|
|
define i32 @test_3preds_constphi(i32* %a, i32 %v, i1 %c1, i1 %c2, i1 %c3) {
|
|
Header:
|
|
br i1 %c1, label %Tail, label %TBB1
|
|
|
|
TBB1:
|
|
br i1 %c2, label %Tail, label %TBB2
|
|
|
|
TBB2:
|
|
br i1 %c3, label %Tail, label %End
|
|
|
|
Tail:
|
|
%p = phi i32[1,%Header], [2, %TBB1], [3, %TBB2]
|
|
%r = call i32 @callee(i32* %a, i32 %v, i32 %p)
|
|
ret i32 %r
|
|
|
|
End:
|
|
ret i32 %v
|
|
}
|
|
|
|
;CHECK-LABEL: @test_indirectbr_phi
|
|
;CHECK-NOT: Tail.predBB1.split:
|
|
;CHECK-NOT: Tail.predBB2.split:
|
|
;CHECK-LABEL: Tail:
|
|
;CHECK: %r = call i32 @callee(i32* %a, i32 %v, i32 %p)
|
|
;CHECK: ret i32 %r
|
|
define i32 @test_indirectbr_phi(i8* %address, i32* %a, i32* %b, i32 %v) {
|
|
Header:
|
|
%indirect.goto.dest = select i1 undef, i8* blockaddress(@test_indirectbr_phi, %End), i8* %address
|
|
indirectbr i8* %indirect.goto.dest, [label %TBB, label %Tail]
|
|
|
|
TBB:
|
|
%indirect.goto.dest2 = select i1 undef, i8* blockaddress(@test_indirectbr_phi, %End), i8* %address
|
|
indirectbr i8* %indirect.goto.dest2, [label %Tail, label %End]
|
|
|
|
Tail:
|
|
%p = phi i32[1,%Header], [2, %TBB]
|
|
%r = call i32 @callee(i32* %a, i32 %v, i32 %p)
|
|
ret i32 %r
|
|
|
|
End:
|
|
ret i32 %v
|
|
}
|
|
|
|
define i32 @callee(i32* %a, i32 %v, i32 %p) {
|
|
entry:
|
|
%c = icmp ne i32* %a, null
|
|
br i1 %c, label %BB1, label %BB2
|
|
|
|
BB1:
|
|
call void @dummy(i32* %a, i32 %p)
|
|
br label %End
|
|
|
|
BB2:
|
|
call void @dummy2(i32 %v, i32 %p)
|
|
br label %End
|
|
|
|
End:
|
|
ret i32 %p
|
|
}
|
|
|
|
declare void @dummy(i32*, i32)
|
|
declare void @dummy2(i32, i32)
|