; Test MD_prof validation

; RUN: split-file %s %t

; RUN: opt -passes=verify %t/valid.ll --disable-output

; RUN: not opt -passes=verify %t/wrong-count.ll --disable-output 2>&1 | FileCheck %s --check-prefix=WRONG-COUNT
; RUN: not opt -passes=verify %t/invalid-name1.ll --disable-output 2>&1 | FileCheck %s
; RUN: not opt -passes=verify %t/invalid-name2.ll --disable-output 2>&1 | FileCheck %s

; RUN: opt -passes=verify %t/unknown-correct.ll --disable-output

; RUN: not opt -passes=verify %t/unknown-invalid.ll --disable-output 2>&1 | FileCheck %s --check-prefix=EXTRA-ARGS
; RUN: not opt -passes=verify %t/unknown-noargs.ll --disable-output 2>&1 | FileCheck %s --check-prefix=NO-ARGS
; RUN: not opt -passes=verify %t/unknown-empty.ll --disable-output 2>&1 | FileCheck %s --check-prefix=EMPTY-ARGS
; RUN: opt -passes=verify %t/unknown-on-function1.ll -S -o - | FileCheck %s --check-prefix=ON-FUNCTION1
; RUN: not opt -passes=verify %t/unknown-on-function2.ll --disable-output 2>&1 | FileCheck %s --check-prefix=ON-FUNCTION2
; RUN: not opt -passes=verify %t/invalid-unknown-placement.ll --disable-output 2>&1 | FileCheck %s --check-prefix=INVALID-UNKNOWN-PLACEMENT

;--- valid.ll
declare void @to_invoke()
declare i32 @__gxx_personality_v0(...)

define void @invoker() personality ptr @__gxx_personality_v0 {
  invoke void @to_invoke() to label %exit unwind label %lpad, !prof !0
lpad:
  %ll = landingpad {ptr, i32}
  cleanup
  ret void
exit:
  ret void
}

define i32 @test(i32 %a) {
  %c = icmp eq i32 %a, 0
  br i1 %c, label %yes, label %exit, !prof !0
yes:
  switch i32 %a, label %exit [ i32 1, label %case_b
                               i32 2, label %case_c], !prof !1
case_b:
  br label %exit
case_c:
  br label %exit
exit:
  %r = select i1 %c, i32 1, i32 2, !prof !0
  ret i32 %r
}
!0 = !{!"branch_weights", i32 1, i32 2}
!1 = !{!"branch_weights", i32 1, i32 2, i32 3}

;--- wrong-count.ll
define void @test(i32 %a) {
  %c = icmp eq i32 %a, 0
  br i1 %c, label %yes, label %no, !prof !0
yes:
  ret void
no:
  ret void
}
!0 = !{!"branch_weights", i32 1, i32 2, i32 3}

; WRONG-COUNT: Wrong number of operands

;--- invalid-name1.ll
define void @test(i1 %0) {
  br i1 %0, label %2, label %3, !prof !0
2:
  ret void
3:
  ret void
}
!0 = !{!"invalid", i32 1, i32 2}

;--- invalid-name2.ll
define void @test(i1 %0) {
  br i1 %0, label %2, label %3, !prof !0
2:
  ret void
3:
  ret void
}

!0 = !{!"function_entry_count", i32 1}

; CHECK: expected either branch_weights or VP profile name

;--- unknown-correct.ll
declare void @to_invoke()
declare i32 @__gxx_personality_v0(...)

define void @invoker() personality ptr @__gxx_personality_v0 {
  invoke void @to_invoke() to label %exit unwind label %lpad, !prof !0
lpad:
  %ll = landingpad {ptr, i32}
  cleanup
  ret void
exit:
  ret void
}

define i32 @test(i32 %a) {
  %c = icmp eq i32 %a, 0
  br i1 %c, label %yes, label %exit, !prof !0
yes:
  switch i32 %a, label %exit [ i32 1, label %case_b
                               i32 2, label %case_c], !prof !0
case_b:
  br label %exit
case_c:
  br label %exit
exit:
  %r = select i1 %c, i32 1, i32 2, !prof !0
  ret i32 %r
}

!0 = !{!"unknown", !"test"}

;--- unknown-invalid.ll
define void @test(i32 %a) {
  %c = icmp eq i32 %a, 0
  br i1 %c, label %yes, label %no, !prof !0
yes:
  ret void
no:
  ret void
}

!0 = !{!"unknown", i32 12, i32 67}
; EXTRA-ARGS: 'unknown' !prof should have a single additional operand

;--- unknown-on-function1.ll
define void @test() !prof !0 {
  ret void
}

!0 = !{!"unknown", !"test"}
; ON-FUNCTION1: define void @test() !prof !0

;--- unknown-on-function2.ll
define void @test() !prof !0 {
  ret void
}

!0 = !{!"unknown", i64 123}
; ON-FUNCTION2: 'unknown' !prof should have an additional operand of type string

;--- invalid-unknown-placement.ll
define i32 @test() {
  %r = add i32 1, 2, !prof !0
  ret i32 %r
}
!0 = !{!"unknown", !"test"}
; INVALID-UNKNOWN-PLACEMENT: 'unknown' !prof should only appear on instructions on which 'branch_weights' would

;--- unknown-noargs.ll
define void @test(i32 %a) {
  %c = icmp eq i32 %a, 0
  br i1 %c, label %yes, label %no, !prof !0
yes:
  ret void
no:
  ret void
}

!0 = !{!"unknown"}
; NO-ARGS: 'unknown' !prof should have a single additional operand

;--- unknown-empty.ll
define void @test(i32 %a) {
  %c = icmp eq i32 %a, 0
  br i1 %c, label %yes, label %no, !prof !0
yes:
  ret void
no:
  ret void
}

!0 = !{!"unknown", !""}
; EMPTY-ARGS: the 'unknown' !prof operand should not be an empty string
