blob: c5e9488b90480208c1614a5692fcd44c5663a2f6 [file] [edit]
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
; RUN: opt -S -passes=mergefunc < %s | FileCheck %s
;
; Verify that MergeFunctions correctly merges value profile (VP) metadata
; on indirect calls when combining structurally identical functions.
; Because FunctionComparator only considers functions equivalent when
; their control-flow structure and instruction ordering match exactly,
; MergeFunctions can walk the two functions in parallel and safely merge
; instruction-level metadata.
;
; Value profile counts are already absolute. The pass combines profiles by
; adding counts for targets that appear in both functions and preserving
; targets that appear in only one.
; --------------------------------------------------------------------------
; Both functions provide value profile metadata for the indirect call.
;
; vp_both_a has an entry count of 100 and a profile of:
; {111:60, 222:40}
;
; vp_both_b has an entry count of 200 and a profile of:
; {111:120, 333:80}
;
; After merging, counts for shared targets are summed while unique
; targets are carried over:
;
; entry count = 300
; VP {111:180, 333:80, 222:40}
; --------------------------------------------------------------------------
define internal i32 @vp_both_a(ptr %fn) !prof !1 {
; CHECK-LABEL: define internal i32 @vp_both_a(
; CHECK-SAME: ptr [[FN:%.*]]) !prof [[PROF0:![0-9]+]] {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[FN_VAL:%.*]] = load ptr, ptr [[FN]], align 8
; CHECK-NEXT: [[R:%.*]] = call i32 [[FN_VAL]](), !prof [[PROF1:![0-9]+]]
; CHECK-NEXT: ret i32 [[R]]
;
entry:
%fn_val = load ptr, ptr %fn
%r = call i32 %fn_val(), !prof !2
ret i32 %r
}
define internal i32 @vp_both_b(ptr %fn) !prof !3 {
entry:
%fn_val = load ptr, ptr %fn
%r = call i32 %fn_val(), !prof !4
ret i32 %r
}
; --------------------------------------------------------------------------
; Only one of the functions provides value profile metadata for the
; indirect call.
;
; vp_one_a has an entry count of 30 but does not contain any VP data
; on the call site.
;
; vp_one_b has an entry count of 70 and records the target profile:
; {888:50}
;
; Since only vp_one_b contributes value profile information, the merged
; function carries that profile forward unchanged while combining the
; overall entry counts.
;
; entry count = 100
; VP {888:50}
; --------------------------------------------------------------------------
define internal i32 @vp_one_a(ptr %fn) !prof !5 {
; CHECK-LABEL: define internal i32 @vp_one_a(
; CHECK-SAME: ptr [[FN:%.*]]) !prof [[PROF2:![0-9]+]] {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[FN_VAL:%.*]] = load ptr, ptr [[FN]], align 8
; CHECK-NEXT: [[R:%.*]] = call i32 [[FN_VAL]](), !prof [[PROF3:![0-9]+]]
; CHECK-NEXT: [[ADJ:%.*]] = add i32 [[R]], 3
; CHECK-NEXT: ret i32 [[ADJ]]
;
entry:
%fn_val = load ptr, ptr %fn
%r = call i32 %fn_val()
%adj = add i32 %r, 3
ret i32 %adj
}
define internal i32 @vp_one_b(ptr %fn) !prof !6 {
entry:
%fn_val = load ptr, ptr %fn
%r = call i32 %fn_val(), !prof !7
%adj = add i32 %r, 3
ret i32 %adj
}
; --------------------------------------------------------------------------
; Both functions attach value profile metadata to the indirect call, but
; they use different VP kinds.
;
; Because the profiles are not compatible, MergeFunctions cannot safely
; merge them into a single representation. Rather than producing
; potentially misleading profile data, the pass drops the call-site
; !prof metadata during the merge.
; --------------------------------------------------------------------------
define internal i32 @vp_kind_a(ptr %fn) !prof !8 {
; CHECK-LABEL: define internal i32 @vp_kind_a(
; CHECK-SAME: ptr [[FN:%.*]]) !prof [[PROF2]] {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[FN_VAL:%.*]] = load ptr, ptr [[FN]], align 8
; CHECK-NEXT: [[R:%.*]] = call i32 [[FN_VAL]]()
; CHECK-NEXT: [[ADJ:%.*]] = add i32 [[R]], 2
; CHECK-NEXT: ret i32 [[ADJ]]
;
entry:
%fn_val = load ptr, ptr %fn
%r = call i32 %fn_val(), !prof !9
%adj = add i32 %r, 2
ret i32 %adj
}
define internal i32 @vp_kind_b(ptr %fn) !prof !10 {
entry:
%fn_val = load ptr, ptr %fn
%r = call i32 %fn_val(), !prof !11
%adj = add i32 %r, 2
ret i32 %adj
}
!1 = !{!"function_entry_count", i64 100}
!2 = !{!"VP", i32 0, i64 100, i64 111, i64 60, i64 222, i64 40}
!3 = !{!"function_entry_count", i64 200}
!4 = !{!"VP", i32 0, i64 200, i64 111, i64 120, i64 333, i64 80}
!5 = !{!"function_entry_count", i64 30}
!6 = !{!"function_entry_count", i64 70}
!7 = !{!"VP", i32 0, i64 70, i64 888, i64 50}
!8 = !{!"function_entry_count", i64 30}
!9 = !{!"VP", i32 0, i64 30, i64 666, i64 20}
!10 = !{!"function_entry_count", i64 70}
!11 = !{!"VP", i32 1, i64 70, i64 777, i64 50}
;.
; CHECK: [[PROF0]] = !{!"function_entry_count", i64 300}
; CHECK: [[PROF1]] = !{!"VP", i32 0, i64 300, i64 111, i64 180, i64 333, i64 80, i64 222, i64 40}
; CHECK: [[PROF2]] = !{!"function_entry_count", i64 100}
; CHECK: [[PROF3]] = !{!"VP", i32 0, i64 50, i64 888, i64 50}
;.