492 changes: 492 additions & 0 deletions llvm/lib/Transforms/Scalar/CallSiteSplitting.cpp

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions llvm/lib/Transforms/Scalar/Scalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ void llvm::initializeScalarOpts(PassRegistry &Registry) {
initializeADCELegacyPassPass(Registry);
initializeBDCELegacyPassPass(Registry);
initializeAlignmentFromAssumptionsPass(Registry);
initializeCallSiteSplittingLegacyPassPass(Registry);
initializeConstantHoistingLegacyPassPass(Registry);
initializeConstantPropagationPass(Registry);
initializeCorrelatedValuePropagationPass(Registry);
Expand Down
1 change: 1 addition & 0 deletions llvm/test/Other/new-pm-defaults.ll
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
; CHECK-O-NEXT: Running pass: EarlyCSEPass
; CHECK-O-NEXT: Running analysis: TargetLibraryAnalysis
; CHECK-O-NEXT: Running pass: LowerExpectIntrinsicPass
; CHECK-O3-NEXT: Running pass: CallSiteSplittingPass
; CHECK-O-NEXT: Finished llvm::Function pass manager run.
; CHECK-O-NEXT: Running pass: IPSCCPPass
; CHECK-O-NEXT: Running pass: CalledValuePropagationPass
Expand Down
9 changes: 7 additions & 2 deletions llvm/test/Other/new-pm-lto-defaults.ll
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,14 @@
; CHECK-O-NEXT: Running pass: ForceFunctionAttrsPass
; CHECK-O-NEXT: Running pass: InferFunctionAttrsPass
; CHECK-O-NEXT: Running analysis: TargetLibraryAnalysis
; CHECK-O2-NEXT: Running pass: ModuleToFunctionPassAdaptor<{{.*}}PassManager{{.*}}>
; CHECK-O2-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}Module
; CHECK-O2-NEXT: Starting llvm::Function pass manager run.
; CHECK-O2-NEXT: Running pass: CallSiteSplittingPass on foo
; CHECK-O2-NEXT: Running analysis: TargetLibraryAnalysis on foo
; CHECK-O2-NEXT: Finished llvm::Function pass manager run.
; CHECK-O2-NEXT: PGOIndirectCallPromotion
; CHECK-O2-NEXT: Running analysis: ProfileSummaryAnalysis
; CHECK-O2-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}Function
; CHECK-O2-NEXT: Running analysis: OptimizationRemarkEmitterAnalysis
; CHECK-O2-NEXT: Running pass: IPSCCPPass
; CHECK-O2-NEXT: Running pass: CalledValuePropagationPass
Expand All @@ -42,7 +47,7 @@
; CHECK-O-NEXT: Running analysis: FunctionAnalysisManagerCGSCCProxy
; CHECK-O-NEXT: Running analysis: OuterAnalysisManagerProxy<{{.*}}LazyCallGraph{{.*}}>
; CHECK-O-NEXT: Running analysis: AAManager
; CHECK-O-NEXT: Running analysis: TargetLibraryAnalysis
; CHECK-O1-NEXT: Running analysis: TargetLibraryAnalysis
; CHECK-O-NEXT: Running pass: ReversePostOrderFunctionAttrsPass
; CHECK-O-NEXT: Running analysis: CallGraphAnalysis
; CHECK-O-NEXT: Running pass: GlobalSplitPass
Expand Down
1 change: 1 addition & 0 deletions llvm/test/Other/new-pm-thinlto-defaults.ll
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
; CHECK-O-NEXT: Running pass: EarlyCSEPass
; CHECK-O-NEXT: Running analysis: TargetLibraryAnalysis
; CHECK-O-NEXT: Running pass: LowerExpectIntrinsicPass
; CHECK-O3-NEXT: Running pass: CallSiteSplittingPass
; CHECK-O-NEXT: Finished llvm::Function pass manager run.
; CHECK-O-NEXT: Running pass: IPSCCPPass
; CHECK-O-NEXT: Running pass: CalledValuePropagationPass
Expand Down
339 changes: 339 additions & 0 deletions llvm/test/Transforms/CallSiteSplitting/callsite-split-or-phi.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,339 @@
; 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)
119 changes: 119 additions & 0 deletions llvm/test/Transforms/CallSiteSplitting/callsite-split.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
; RUN: opt < %s -callsite-splitting -inline -instcombine -jump-threading -S | FileCheck %s
; RUN: opt < %s -passes='function(callsite-splitting),cgscc(inline),function(instcombine,jump-threading)' -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"

%struct.bitmap = type { i32, %struct.bitmap* }

;CHECK-LABEL: @caller
;CHECK-LABEL: NextCond:
;CHECK: br {{.*}} label %callee.exit
;CHECK-LABEL: CallSiteBB.predBB1.split:
;CHECK: call void @callee(%struct.bitmap* null, %struct.bitmap* null, %struct.bitmap* %b_elt, i1 false)
;CHECK-LABEL: callee.exit:
;CHECK: call void @dummy2(%struct.bitmap* %a_elt)

define void @caller(i1 %c, %struct.bitmap* %a_elt, %struct.bitmap* %b_elt) {
entry:
br label %Top

Top:
%tobool1 = icmp eq %struct.bitmap* %a_elt, null
br i1 %tobool1, label %CallSiteBB, label %NextCond

NextCond:
%cmp = icmp ne %struct.bitmap* %b_elt, null
br i1 %cmp, label %CallSiteBB, label %End

CallSiteBB:
%p = phi i1 [0, %Top], [%c, %NextCond]
call void @callee(%struct.bitmap* %a_elt, %struct.bitmap* %a_elt, %struct.bitmap* %b_elt, i1 %p)
br label %End

End:
ret void
}

define void @callee(%struct.bitmap* %dst_elt, %struct.bitmap* %a_elt, %struct.bitmap* %b_elt, i1 %c) {
entry:
%tobool = icmp ne %struct.bitmap* %a_elt, null
%tobool1 = icmp ne %struct.bitmap* %b_elt, null
%or.cond = and i1 %tobool, %tobool1
br i1 %or.cond, label %Cond, label %Big

Cond:
%cmp = icmp eq %struct.bitmap* %dst_elt, %a_elt
br i1 %cmp, label %Small, label %Big

Small:
call void @dummy2(%struct.bitmap* %a_elt)
br label %End

Big:
call void @dummy1(%struct.bitmap* %a_elt, %struct.bitmap* %a_elt, %struct.bitmap* %a_elt, %struct.bitmap* %a_elt, %struct.bitmap* %a_elt, %struct.bitmap* %a_elt)
call void @dummy1(%struct.bitmap* %a_elt, %struct.bitmap* %a_elt, %struct.bitmap* %a_elt, %struct.bitmap* %a_elt, %struct.bitmap* %a_elt, %struct.bitmap* %a_elt)
call void @dummy1(%struct.bitmap* %a_elt, %struct.bitmap* %a_elt, %struct.bitmap* %a_elt, %struct.bitmap* %a_elt, %struct.bitmap* %a_elt, %struct.bitmap* %a_elt)
call void @dummy1(%struct.bitmap* %a_elt, %struct.bitmap* %a_elt, %struct.bitmap* %a_elt, %struct.bitmap* %a_elt, %struct.bitmap* %a_elt, %struct.bitmap* %a_elt)
call void @dummy1(%struct.bitmap* %a_elt, %struct.bitmap* %a_elt, %struct.bitmap* %a_elt, %struct.bitmap* %a_elt, %struct.bitmap* %a_elt, %struct.bitmap* %a_elt)
call void @dummy1(%struct.bitmap* %a_elt, %struct.bitmap* %a_elt, %struct.bitmap* %a_elt, %struct.bitmap* %a_elt, %struct.bitmap* %a_elt, %struct.bitmap* %a_elt)
call void @dummy1(%struct.bitmap* %a_elt, %struct.bitmap* %a_elt, %struct.bitmap* %a_elt, %struct.bitmap* %a_elt, %struct.bitmap* %a_elt, %struct.bitmap* %a_elt)
br label %End

End:
ret void
}

declare void @dummy2(%struct.bitmap*)
declare void @dummy1(%struct.bitmap*, %struct.bitmap*, %struct.bitmap*, %struct.bitmap*, %struct.bitmap*, %struct.bitmap*)


;CHECK-LABEL: @caller2
;CHECK-LABEL: CallSiteBB.predBB1.split:
;CHECK: call void @dummy4()
;CHECK-LABEL: CallSiteBB.predBB2.split:
;CHECK: call void @dummy3()
;CheCK-LABEL: CallSiteBB:
;CHECK: %phi.call = phi i1 [ false, %CallSiteBB.predBB1.split ], [ true, %CallSiteBB.predBB2.split ]
;CHECK: call void @foo(i1 %phi.call)
define void @caller2(i1 %c, %struct.bitmap* %a_elt, %struct.bitmap* %b_elt, %struct.bitmap* %c_elt) {
entry:
br label %Top

Top:
%tobool1 = icmp eq %struct.bitmap* %a_elt, %b_elt
br i1 %tobool1, label %CallSiteBB, label %NextCond

NextCond:
%cmp = icmp ne %struct.bitmap* %b_elt, %c_elt
br i1 %cmp, label %CallSiteBB, label %End

CallSiteBB:
%phi = phi i1 [0, %Top],[1, %NextCond]
%u = call i1 @callee2(i1 %phi)
call void @foo(i1 %u)
br label %End

End:
ret void
}

define i1 @callee2(i1 %b) {
entry:
br i1 %b, label %BB1, label %BB2

BB1:
call void @dummy3()
br label %End

BB2:
call void @dummy4()
br label %End

End:
ret i1 %b
}

declare void @dummy3()
declare void @dummy4()
declare void @foo(i1)