llvm/llvm/test/Transforms/CallSiteSplitting/callsite-instructions-before-call.ll

; RUN: opt -S -passes=callsite-splitting < %s | FileCheck --check-prefix=CHECK %s
; RUN: opt -S -passes=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 ptr @test_split_branch_phi(ptr %ptrarg, i32 %i) {
Header:
  %tobool = icmp ne ptr %ptrarg, null
  br i1 %tobool, label %TBB, label %CallSite

TBB:                                    ; preds = %Header
  %arrayidx = getelementptr inbounds i32, ptr %ptrarg, i64 42
  %0 = load i32, ptr %arrayidx, align 4
  %tobool1 = icmp ne i32 %0, 0
  br i1 %tobool1, label %CallSite, label %End

CallSite:                                          ; preds = %TBB, %Header
  %somepointer = getelementptr i32, ptr %ptrarg, i64 18
  call void @bar(ptr %ptrarg, i32 %i)
  br label %End

End:                                           ; preds = %CallSite, %TBB
  %somepointerphi = phi ptr [ %somepointer, %CallSite ], [ null, %TBB ]
  ret ptr %somepointerphi
}
; NODUP-LABEL: test_split_branch_phi
; NODUP-NOT: split
; CHECK-LABEL: Header.split
; CHECK: %[[V1:somepointer[0-9]+]] = getelementptr i32, ptr %ptrarg, i64 18
; CHECK: call void @bar(ptr null, i32 %i)
; CHECK: br label %CallSite
; CHECK-LABEL: TBB.split:
; CHECK: %[[V2:somepointer[0-9]+]] = getelementptr i32, ptr %ptrarg, i64 18
; CHECK: call void @bar(ptr nonnull %ptrarg, i32 %i)
; CHECK: br label %CallSite
; CHECK: CallSite:
; CHECK: phi ptr [ %[[V1]], %Header.split ], [ %[[V2]], %TBB.split ]


define void @split_branch_no_extra_phi(ptr %ptrarg, i32 %i) {
Header:
  %tobool = icmp ne ptr %ptrarg, null
  br i1 %tobool, label %TBB, label %CallSite

TBB:                                    ; preds = %Header
  %arrayidx = getelementptr inbounds i32, ptr %ptrarg, i64 42
  %0 = load i32, ptr %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(ptr %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(ptr null, i32 %[[V1]])
; CHECK: br label %CallSite
; CHECK-LABEL: TBB.split:
; CHECK: %[[V2:.+]] = add i32 %i, 99
; CHECK: call void @bar(ptr 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(ptr %ptrarg, i32 %i) {
Header:
  %tobool = icmp ne ptr %ptrarg, null
  br i1 %tobool, label %TBB, label %CallSite

TBB:                                    ; preds = %Header
  %arrayidx = getelementptr inbounds i32, ptr %ptrarg, i64 42
  %0 = load i32, ptr %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(ptr %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(ptr %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(ptr %ptrarg, i32 %i) {
Header:
  %l1 = load i32, ptr undef, align 16
  %tobool = icmp ne ptr %ptrarg, null
  br i1 %tobool, label %TBB, label %CallSite

TBB:                                    ; preds = %Header
  %arrayidx = getelementptr inbounds i32, ptr %ptrarg, i64 42
  %0 = load i32, ptr %arrayidx, align 4
  %l2 = load i32, ptr 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(ptr %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(ptr null, i32 %l1)
; CHECK: br label %CallSite
; CHECK-LABEL: TBB.split:
; CHECK: call void @bar(ptr 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(ptr %ptrarg, i32 %i) {
Header:
  %tobool = icmp ne ptr %ptrarg, null
  br i1 %tobool, label %TBB, label %CallSite

TBB:
  br i1 undef, label %CallSite, label %End

CallSite:
  %arrayidx112 = getelementptr inbounds i32, ptr undef, i64 1
  %0 = load i32, ptr %arrayidx112, align 4
  call void @bar(ptr %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, ptr
; CHECK: call void @bar(ptr null, i32 %i)
; CHECK: br label %CallSite
; CHECK-LABEL: TBB.split:
; CHECK: %[[V2:.+]] = load i32, ptr
; CHECK: call void @bar(ptr 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(ptr %a, i32 %v) {
Header:
  %tobool1 = icmp eq ptr %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, ptr %a
  %r = call i32 @callee(ptr %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, ptr %a
; CHECK-NEXT: %[[CALL1:.*]] = call i32 @callee(ptr null, i32 %v, i32 1)
; CHECK-NEXT: br label %Tail
; CHECK-LABEL: TBB.split:
; CHECK-NEXT: store i32 %v, ptr %a
; CHECK-NEXT: %[[CALL2:.*]] = call i32 @callee(ptr 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(ptr %a, i32 %v, i32 %p) {
    ret i32 0
}

define void @test_no_remove_used_phi(ptr %ptrarg, i32 %i) {
Header:
  %l1 = load i32, ptr undef, align 16
  %tobool = icmp ne ptr %ptrarg, null
  br i1 %tobool, label %TBB, label %CallSite

TBB:                                    ; preds = %Header
  %arrayidx = getelementptr inbounds i32, ptr %ptrarg, i64 42
  %0 = load i32, ptr %arrayidx, align 4
  %l2 = load i32, ptr 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(ptr %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(ptr null, i32 %l1)
; CHECK-NEXT: br label %CallSite
; CHECK-LABEL: TBB.split:
; CHECK: call void @bar(ptr 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(ptr, i32) {
    ret void
}

define  void @bari(i32) {
    ret void
}