; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt -S < %s -passes=slp-vectorizer -mtriple=riscv64 -mattr=+v | FileCheck %s

declare void @g()

; Shouldn't be vectorized
define void @f0(i1 %c, ptr %p, ptr %q) {
; CHECK-LABEL: define void @f0(
; CHECK-SAME: i1 [[C:%.*]], ptr [[P:%.*]], ptr [[Q:%.*]]) #[[ATTR0:[0-9]+]] {
; CHECK-NEXT:    [[X0:%.*]] = load i64, ptr [[P]], align 8
; CHECK-NEXT:    [[P1:%.*]] = getelementptr i64, ptr [[P]], i64 1
; CHECK-NEXT:    [[X1:%.*]] = load i64, ptr [[P1]], align 8
; CHECK-NEXT:    br i1 [[C]], label %[[FOO:.*]], label %[[BAR:.*]]
; CHECK:       [[FOO]]:
; CHECK-NEXT:    call void @g()
; CHECK-NEXT:    call void @g()
; CHECK-NEXT:    call void @g()
; CHECK-NEXT:    br label %[[BAZ:.*]]
; CHECK:       [[BAR]]:
; CHECK-NEXT:    call void @g()
; CHECK-NEXT:    call void @g()
; CHECK-NEXT:    call void @g()
; CHECK-NEXT:    br label %[[BAZ]]
; CHECK:       [[BAZ]]:
; CHECK-NEXT:    store i64 [[X0]], ptr [[Q]], align 8
; CHECK-NEXT:    [[Q1:%.*]] = getelementptr i64, ptr [[Q]], i64 1
; CHECK-NEXT:    store i64 [[X1]], ptr [[Q1]], align 8
; CHECK-NEXT:    ret void
;
  %x0 = load i64, ptr %p
  %p1 =  getelementptr i64, ptr %p, i64 1
  %x1 = load i64, ptr %p1
  br i1 %c, label %foo, label %bar
foo:
  call void @g()
  call void @g()
  call void @g()
  br label %baz
bar:
  call void @g()
  call void @g()
  call void @g()
  br label %baz
baz:
  store i64 %x0, ptr %q
  %q1 =  getelementptr i64, ptr %q, i64 1
  store i64 %x1, ptr %q1

  ret void
}

; Should be vectorized - just one spill of TMP0
define void @f1(i1 %c, ptr %p, ptr %q, ptr %r) {
; CHECK-LABEL: define void @f1(
; CHECK-SAME: i1 [[C:%.*]], ptr [[P:%.*]], ptr [[Q:%.*]], ptr [[R:%.*]]) #[[ATTR0]] {
; CHECK-NEXT:  [[ENTRY:.*:]]
; CHECK-NEXT:    [[TMP0:%.*]] = load <2 x i64>, ptr [[P]], align 8
; CHECK-NEXT:    br i1 [[C]], label %[[FOO:.*]], label %[[BAR:.*]]
; CHECK:       [[FOO]]:
; CHECK-NEXT:    [[TMP1:%.*]] = add <2 x i64> [[TMP0]], splat (i64 1)
; CHECK-NEXT:    br label %[[BAZ:.*]]
; CHECK:       [[BAR]]:
; CHECK-NEXT:    call void @g()
; CHECK-NEXT:    call void @g()
; CHECK-NEXT:    call void @g()
; CHECK-NEXT:    br label %[[BAZ]]
; CHECK:       [[BAZ]]:
; CHECK-NEXT:    [[TMP2:%.*]] = phi <2 x i64> [ [[TMP1]], %[[FOO]] ], [ [[TMP0]], %[[BAR]] ]
; CHECK-NEXT:    store <2 x i64> [[TMP2]], ptr [[Q]], align 8
; CHECK-NEXT:    ret void
;
entry:
  %x0 = load i64, ptr %p
  %p1 =  getelementptr i64, ptr %p, i64 1
  %x1 = load i64, ptr %p1
  br i1 %c, label %foo, label %bar
foo:
  %y0 = add i64 %x0, 1
  %y1 = add i64 %x1, 1
  br label %baz
bar:
  call void @g()
  call void @g()
  call void @g()
  br label %baz
baz:
  %phi0 = phi i64 [%y0, %foo], [%x0, %bar]
  %phi1 = phi i64 [%y1, %foo], [%x1, %bar]
  store i64 %phi0, ptr %q
  %q1 =  getelementptr i64, ptr %q, i64 1
  store i64 %phi1, ptr %q1

  ret void
}

; Shouldn't be vectorized
define void @f11(i1 %c, ptr %p, ptr %q, ptr %r) {
; CHECK-LABEL: define void @f11(
; CHECK-SAME: i1 [[C:%.*]], ptr [[P:%.*]], ptr [[Q:%.*]], ptr [[R:%.*]]) #[[ATTR0]] {
; CHECK-NEXT:  [[ENTRY:.*:]]
; CHECK-NEXT:    [[X0:%.*]] = load i64, ptr [[P]], align 8
; CHECK-NEXT:    [[P1:%.*]] = getelementptr i64, ptr [[P]], i64 1
; CHECK-NEXT:    [[X1:%.*]] = load i64, ptr [[P1]], align 8
; CHECK-NEXT:    br i1 [[C]], label %[[FOO:.*]], label %[[BAR:.*]]
; CHECK:       [[FOO]]:
; CHECK-NEXT:    br label %[[BAZ:.*]]
; CHECK:       [[BAR]]:
; CHECK-NEXT:    call void @g()
; CHECK-NEXT:    call void @g()
; CHECK-NEXT:    call void @g()
; CHECK-NEXT:    br label %[[BAZ]]
; CHECK:       [[BAZ]]:
; CHECK-NEXT:    [[PHI0:%.*]] = phi i64 [ 0, %[[FOO]] ], [ [[X0]], %[[BAR]] ]
; CHECK-NEXT:    [[PHI1:%.*]] = phi i64 [ 1, %[[FOO]] ], [ [[X1]], %[[BAR]] ]
; CHECK-NEXT:    store i64 [[PHI0]], ptr [[Q]], align 8
; CHECK-NEXT:    [[Q1:%.*]] = getelementptr i64, ptr [[Q]], i64 1
; CHECK-NEXT:    store i64 [[PHI1]], ptr [[Q1]], align 8
; CHECK-NEXT:    ret void
;
entry:
  %x0 = load i64, ptr %p
  %p1 =  getelementptr i64, ptr %p, i64 1
  %x1 = load i64, ptr %p1
  br i1 %c, label %foo, label %bar
foo:
  br label %baz
bar:
  call void @g()
  call void @g()
  call void @g()
  br label %baz
baz:
  %phi0 = phi i64 [0, %foo], [%x0, %bar]
  %phi1 = phi i64 [1, %foo], [%x1, %bar]
  store i64 %phi0, ptr %q
  %q1 =  getelementptr i64, ptr %q, i64 1
  store i64 %phi1, ptr %q1

  ret void
}

; Should be vectorized
define void @f2(i1 %c, ptr %p, ptr %q, ptr %r) {
; CHECK-LABEL: define void @f2(
; CHECK-SAME: i1 [[C:%.*]], ptr [[P:%.*]], ptr [[Q:%.*]], ptr [[R:%.*]]) #[[ATTR0]] {
; CHECK-NEXT:  [[ENTRY:.*]]:
; CHECK-NEXT:    call void @g()
; CHECK-NEXT:    call void @g()
; CHECK-NEXT:    call void @g()
; CHECK-NEXT:    br i1 [[C]], label %[[FOO:.*]], label %[[BAR:.*]]
; CHECK:       [[FOO]]:
; CHECK-NEXT:    [[TMP0:%.*]] = load <2 x i64>, ptr [[P]], align 8
; CHECK-NEXT:    br label %[[BAR]]
; CHECK:       [[BAR]]:
; CHECK-NEXT:    [[TMP1:%.*]] = phi <2 x i64> [ zeroinitializer, %[[ENTRY]] ], [ [[TMP0]], %[[FOO]] ]
; CHECK-NEXT:    store <2 x i64> [[TMP1]], ptr [[Q]], align 8
; CHECK-NEXT:    ret void
;
entry:
  call void @g()
  call void @g()
  call void @g()
  br i1 %c, label %foo, label %bar
foo:
  %x0 = load i64, ptr %p
  %p1 =  getelementptr i64, ptr %p, i64 1
  %x1 = load i64, ptr %p1
  br label %bar
bar:
  %phi0 = phi i64 [0, %entry], [%x0, %foo]
  %phi1 = phi i64 [0, %entry], [%x1, %foo]
  store i64 %phi0, ptr %q
  %q1 =  getelementptr i64, ptr %q, i64 1
  store i64 %phi1, ptr %q1

  ret void
}


; Shouldn't be vectorized
define void @f3(i64 %n, double %f0, double %f1, ptr %q) {
; CHECK-LABEL: define void @f3(
; CHECK-SAME: i64 [[N:%.*]], double [[F0:%.*]], double [[F1:%.*]], ptr [[Q:%.*]]) #[[ATTR0]] {
; CHECK-NEXT:  [[ENTRY:.*]]:
; CHECK-NEXT:    br label %[[LOOP:.*]]
; CHECK:       [[LOOP]]:
; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LATCH:.*]] ]
; CHECK-NEXT:    [[PHI0:%.*]] = phi double [ [[F0]], %[[ENTRY]] ], [ [[X0:%.*]], %[[LATCH]] ]
; CHECK-NEXT:    [[PHI1:%.*]] = phi double [ [[F1]], %[[ENTRY]] ], [ [[X1:%.*]], %[[LATCH]] ]
; CHECK-NEXT:    call void @g()
; CHECK-NEXT:    call void @g()
; CHECK-NEXT:    call void @g()
; CHECK-NEXT:    br label %[[LATCH]]
; CHECK:       [[LATCH]]:
; CHECK-NEXT:    [[X0]] = fadd double [[PHI0]], 1.000000e+00
; CHECK-NEXT:    [[X1]] = fadd double [[PHI1]], 1.000000e+00
; CHECK-NEXT:    [[IV_NEXT]] = add i64 [[IV]], 1
; CHECK-NEXT:    [[DONE:%.*]] = icmp eq i64 [[IV_NEXT]], [[N]]
; CHECK-NEXT:    br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP]]
; CHECK:       [[EXIT]]:
; CHECK-NEXT:    [[Q_GEP0:%.*]] = getelementptr i64, ptr [[Q]], i64 [[IV]]
; CHECK-NEXT:    store double [[X0]], ptr [[Q_GEP0]], align 8
; CHECK-NEXT:    [[Q_GEP1:%.*]] = getelementptr i64, ptr [[Q_GEP0]], i64 1
; CHECK-NEXT:    store double [[X1]], ptr [[Q_GEP1]], align 8
; CHECK-NEXT:    ret void
;
entry:
  br label %loop
loop:
  %iv = phi i64 [0, %entry], [%iv.next, %latch]
  %phi0 = phi double [%f0, %entry], [%x0, %latch]
  %phi1 = phi double [%f1, %entry], [%x1, %latch]
  call void @g()
  call void @g()
  call void @g()
  br label %latch
latch:
  %x0 = fadd double %phi0, 1.0
  %x1 = fadd double %phi1, 1.0

  %iv.next = add i64 %iv, 1
  %done = icmp eq i64 %iv.next, %n
  br i1 %done, label %exit, label %loop
exit:
  %q.gep0 =  getelementptr i64, ptr %q, i64 %iv
  store double %x0, ptr %q.gep0
  %q.gep1 =  getelementptr i64, ptr %q.gep0, i64 1
  store double %x1, ptr %q.gep1
  ret void
}

; Should be vectorized
define void @f4(ptr %p, ptr %q, i1 %c0, i1 %c1) {
; CHECK-LABEL: define void @f4(
; CHECK-SAME: ptr [[P:%.*]], ptr [[Q:%.*]], i1 [[C0:%.*]], i1 [[C1:%.*]]) #[[ATTR0]] {
; CHECK-NEXT:  [[ENTRY:.*:]]
; CHECK-NEXT:    br label %[[FOO:.*]]
; CHECK:       [[FOO]]:
; CHECK-NEXT:    call void @g()
; CHECK-NEXT:    call void @g()
; CHECK-NEXT:    call void @g()
; CHECK-NEXT:    br label %[[BAR:.*]]
; CHECK:       [[BAR]]:
; CHECK-NEXT:    [[TMP0:%.*]] = load <2 x i64>, ptr [[P]], align 8
; CHECK-NEXT:    br i1 [[C0]], label %[[BAZ:.*]], label %[[QUX:.*]]
; CHECK:       [[BAZ]]:
; CHECK-NEXT:    [[TMP1:%.*]] = add <2 x i64> [[TMP0]], splat (i64 1)
; CHECK-NEXT:    br label %[[QUX]]
; CHECK:       [[QUX]]:
; CHECK-NEXT:    [[TMP2:%.*]] = phi <2 x i64> [ [[TMP0]], %[[BAR]] ], [ [[TMP1]], %[[BAZ]] ]
; CHECK-NEXT:    store <2 x i64> [[TMP2]], ptr [[Q]], align 8
; CHECK-NEXT:    br i1 [[C1]], label %[[FOO]], label %[[BAR]]
;
entry:
  br label %foo
foo:
  call void @g()
  call void @g()
  call void @g()
  br label %bar
bar:
  %x0 = load i64, ptr %p
  %p1 =  getelementptr i64, ptr %p, i64 1
  %x1 = load i64, ptr %p1
  br i1 %c0, label %baz, label %qux
baz:
  %y0 = add i64 %x0, 1
  %y1 = add i64 %x1, 1
  br label %qux
qux:
  %z0 = phi i64 [%x0, %bar], [%y0, %baz]
  %z1 = phi i64 [%x1, %bar], [%y1, %baz]
  store i64 %z0, ptr %q
  %q1 =  getelementptr i64, ptr %q, i64 1
  store i64 %z1, ptr %q1
  br i1 %c1, label %foo, label %bar
}


; Should be vectorized
define void @f5(i1 %c0, ptr %p, ptr %q) {
; CHECK-LABEL: define void @f5(
; CHECK-SAME: i1 [[C0:%.*]], ptr [[P:%.*]], ptr [[Q:%.*]]) #[[ATTR0]] {
; CHECK-NEXT:  [[ENTRY:.*:]]
; CHECK-NEXT:    br label %[[FOO:.*]]
; CHECK:       [[FOO]]:
; CHECK-NEXT:    call void @g()
; CHECK-NEXT:    call void @g()
; CHECK-NEXT:    call void @g()
; CHECK-NEXT:    [[TMP0:%.*]] = load <2 x i64>, ptr [[P]], align 8
; CHECK-NEXT:    br i1 [[C0]], label %[[BAR:.*]], label %[[FOOBAR:.*]]
; CHECK:       [[BAR]]:
; CHECK-NEXT:    br label %[[BAZ:.*]]
; CHECK:       [[BAZ]]:
; CHECK-NEXT:    [[TMP1:%.*]] = add <2 x i64> [[TMP0]], splat (i64 1)
; CHECK-NEXT:    br label %[[BARFOO:.*]]
; CHECK:       [[FOOBAR]]:
; CHECK-NEXT:    [[TMP2:%.*]] = add <2 x i64> [[TMP0]], splat (i64 2)
; CHECK-NEXT:    br label %[[BARFOO]]
; CHECK:       [[BARFOO]]:
; CHECK-NEXT:    [[TMP3:%.*]] = phi <2 x i64> [ [[TMP2]], %[[FOOBAR]] ], [ [[TMP1]], %[[BAZ]] ]
; CHECK-NEXT:    store <2 x i64> [[TMP3]], ptr [[Q]], align 8
; CHECK-NEXT:    br label %[[FOO]]
;
entry:
  br label %foo
foo:
  call void @g()
  call void @g()
  call void @g()
  %x0 = load i64, ptr %p
  %p1 =  getelementptr i64, ptr %p, i64 1
  %x1 = load i64, ptr %p1
  br i1 %c0, label %bar, label %foobar
bar:
  br label %baz
baz:
  %y0 = add i64 %x0, 1
  %y1 = add i64 %x1, 1
  br label %barfoo
foobar:
  %z0 = add i64 %x0, 2
  %z1 = add i64 %x1, 2
  br label %barfoo
barfoo:
  %phi0 = phi i64 [%z0, %foobar], [%y0, %baz]
  %phi1 = phi i64 [%z1, %foobar], [%y1, %baz]
  store i64 %phi0, ptr %q
  %q1 =  getelementptr i64, ptr %q, i64 1
  store i64 %phi1, ptr %q1
  br label %foo
}

; Shouldn't be vectorized
define void @f6(i1 %c, ptr %p, ptr %q, ptr %r) {
; CHECK-LABEL: define void @f6(
; CHECK-SAME: i1 [[C:%.*]], ptr [[P:%.*]], ptr [[Q:%.*]], ptr [[R:%.*]]) #[[ATTR0]] {
; CHECK-NEXT:  [[ENTRY:.*]]:
; CHECK-NEXT:    br i1 [[C]], label %[[FOO:.*]], label %[[BAR:.*]]
; CHECK:       [[FOO]]:
; CHECK-NEXT:    [[X0:%.*]] = load i64, ptr [[P]], align 8
; CHECK-NEXT:    [[P1:%.*]] = getelementptr i64, ptr [[P]], i64 1
; CHECK-NEXT:    [[X1:%.*]] = load i64, ptr [[P1]], align 8
; CHECK-NEXT:    br label %[[BAR]]
; CHECK:       [[BAR]]:
; CHECK-NEXT:    [[PHI0:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[X0]], %[[FOO]] ]
; CHECK-NEXT:    [[PHI1:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[X1]], %[[FOO]] ]
; CHECK-NEXT:    call void @g()
; CHECK-NEXT:    call void @g()
; CHECK-NEXT:    call void @g()
; CHECK-NEXT:    br label %[[BAZ:.*]]
; CHECK:       [[BAZ]]:
; CHECK-NEXT:    store i64 [[PHI0]], ptr [[Q]], align 8
; CHECK-NEXT:    [[Q1:%.*]] = getelementptr i64, ptr [[Q]], i64 1
; CHECK-NEXT:    store i64 [[PHI1]], ptr [[Q1]], align 8
; CHECK-NEXT:    ret void
;
entry:
  br i1 %c, label %foo, label %bar
foo:
  %x0 = load i64, ptr %p
  %p1 =  getelementptr i64, ptr %p, i64 1
  %x1 = load i64, ptr %p1
  br label %bar
bar:
  %phi0 = phi i64 [0, %entry], [%x0, %foo]
  %phi1 = phi i64 [0, %entry], [%x1, %foo]
  call void @g()
  call void @g()
  call void @g()
  br label %baz
baz:
  store i64 %phi0, ptr %q
  %q1 =  getelementptr i64, ptr %q, i64 1
  store i64 %phi1, ptr %q1

  ret void
}

