; RUN: opt -mtriple=amdgcn-amd-amdhsa -basicaa -load-store-vectorizer -S -o - %s | FileCheck %s

target datalayout = "e-p:32:32-p1:64:64-p2:64:64-p3:32:32-p4:64:64-p5:32:32-p24:64:64-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64"

declare i32 @llvm.amdgcn.workitem.id.x() #1

; CHECK-LABEL: @basic_merge_sext_index(
; CHECK: sext i32 %id.x to i64
; CHECK: load <2 x float>
; CHECK: store <2 x float> zeroinitializer
define void @basic_merge_sext_index(float addrspace(1)* nocapture %a, float addrspace(1)* nocapture %b, float addrspace(1)* nocapture readonly %c) #0 {
entry:
  %id.x = call i32 @llvm.amdgcn.workitem.id.x()
  %sext.id.x = sext i32 %id.x to i64
  %a.idx.x = getelementptr inbounds float, float addrspace(1)* %a, i64 %sext.id.x
  %c.idx.x = getelementptr inbounds float, float addrspace(1)* %c, i64 %sext.id.x
  %a.idx.x.1 = getelementptr inbounds float, float addrspace(1)* %a.idx.x, i64 1
  %c.idx.x.1 = getelementptr inbounds float, float addrspace(1)* %c.idx.x, i64 1

  %ld.c = load float, float addrspace(1)* %c.idx.x, align 4
  %ld.c.idx.1 = load float, float addrspace(1)* %c.idx.x.1, align 4

  store float 0.0, float addrspace(1)* %a.idx.x, align 4
  store float 0.0, float addrspace(1)* %a.idx.x.1, align 4

  %add = fadd float %ld.c, %ld.c.idx.1
  store float %add, float addrspace(1)* %b, align 4
  ret void
}

; CHECK-LABEL: @basic_merge_zext_index(
; CHECK: zext i32 %id.x to i64
; CHECK: load <2 x float>
; CHECK: store <2 x float>
define void @basic_merge_zext_index(float addrspace(1)* nocapture %a, float addrspace(1)* nocapture %b, float addrspace(1)* nocapture readonly %c) #0 {
entry:
  %id.x = call i32 @llvm.amdgcn.workitem.id.x()
  %zext.id.x = zext i32 %id.x to i64
  %a.idx.x = getelementptr inbounds float, float addrspace(1)* %a, i64 %zext.id.x
  %c.idx.x = getelementptr inbounds float, float addrspace(1)* %c, i64 %zext.id.x
  %a.idx.x.1 = getelementptr inbounds float, float addrspace(1)* %a.idx.x, i64 1
  %c.idx.x.1 = getelementptr inbounds float, float addrspace(1)* %c.idx.x, i64 1

  %ld.c = load float, float addrspace(1)* %c.idx.x, align 4
  %ld.c.idx.1 = load float, float addrspace(1)* %c.idx.x.1, align 4
  store float 0.0, float addrspace(1)* %a.idx.x, align 4
  store float 0.0, float addrspace(1)* %a.idx.x.1, align 4

  %add = fadd float %ld.c, %ld.c.idx.1
  store float %add, float addrspace(1)* %b, align 4
  ret void
}

; CHECK-LABEL: @merge_op_zext_index(
; CHECK: load <2 x float>
; CHECK: store <2 x float>
define void @merge_op_zext_index(float addrspace(1)* nocapture noalias %a, float addrspace(1)* nocapture noalias %b, float addrspace(1)* nocapture readonly noalias %c) #0 {
entry:
  %id.x = call i32 @llvm.amdgcn.workitem.id.x()
  %shl = shl i32 %id.x, 2
  %zext.id.x = zext i32 %shl to i64
  %a.0 = getelementptr inbounds float, float addrspace(1)* %a, i64 %zext.id.x
  %c.0 = getelementptr inbounds float, float addrspace(1)* %c, i64 %zext.id.x

  %id.x.1 = or i32 %shl, 1
  %id.x.1.ext = zext i32 %id.x.1 to i64

  %a.1 = getelementptr inbounds float, float addrspace(1)* %a, i64 %id.x.1.ext
  %c.1 = getelementptr inbounds float, float addrspace(1)* %c, i64 %id.x.1.ext

  %ld.c.0 = load float, float addrspace(1)* %c.0, align 4
  store float 0.0, float addrspace(1)* %a.0, align 4
  %ld.c.1 = load float, float addrspace(1)* %c.1, align 4
  store float 0.0, float addrspace(1)* %a.1, align 4

  %add = fadd float %ld.c.0, %ld.c.1
  store float %add, float addrspace(1)* %b, align 4
  ret void
}

; CHECK-LABEL: @merge_op_sext_index(
; CHECK: load <2 x float>
; CHECK: store <2 x float>
define void @merge_op_sext_index(float addrspace(1)* nocapture noalias %a, float addrspace(1)* nocapture noalias %b, float addrspace(1)* nocapture readonly noalias %c) #0 {
entry:
  %id.x = call i32 @llvm.amdgcn.workitem.id.x()
  %shl = shl i32 %id.x, 2
  %zext.id.x = sext i32 %shl to i64
  %a.0 = getelementptr inbounds float, float addrspace(1)* %a, i64 %zext.id.x
  %c.0 = getelementptr inbounds float, float addrspace(1)* %c, i64 %zext.id.x

  %id.x.1 = or i32 %shl, 1
  %id.x.1.ext = sext i32 %id.x.1 to i64

  %a.1 = getelementptr inbounds float, float addrspace(1)* %a, i64 %id.x.1.ext
  %c.1 = getelementptr inbounds float, float addrspace(1)* %c, i64 %id.x.1.ext

  %ld.c.0 = load float, float addrspace(1)* %c.0, align 4
  store float 0.0, float addrspace(1)* %a.0, align 4
  %ld.c.1 = load float, float addrspace(1)* %c.1, align 4
  store float 0.0, float addrspace(1)* %a.1, align 4

  %add = fadd float %ld.c.0, %ld.c.1
  store float %add, float addrspace(1)* %b, align 4
  ret void
}

; This case fails to vectorize if not using the extra extension
; handling in isConsecutiveAccess.

; CHECK-LABEL: @zext_trunc_phi_1(
; CHECK: loop:
; CHECK: load <2 x i32>
; CHECK: store <2 x i32>
define void @zext_trunc_phi_1(i32 addrspace(1)* nocapture noalias %a, i32 addrspace(1)* nocapture noalias %b, i32 addrspace(1)* nocapture readonly noalias %c, i32 %n, i64 %arst, i64 %aoeu) #0 {
entry:
  %cmp0 = icmp eq i32 %n, 0
  br i1 %cmp0, label %exit, label %loop

loop:
  %indvars.iv = phi i64 [ %indvars.iv.next, %loop ], [ 0, %entry ]
  %trunc.iv = trunc i64 %indvars.iv to i32
  %idx = shl i32 %trunc.iv, 4

  %idx.ext = zext i32 %idx to i64
  %c.0 = getelementptr inbounds i32, i32 addrspace(1)* %c, i64 %idx.ext
  %a.0 = getelementptr inbounds i32, i32 addrspace(1)* %a, i64 %idx.ext

  %idx.1 = or i32 %idx, 1
  %idx.1.ext = zext i32 %idx.1 to i64
  %c.1 = getelementptr inbounds i32, i32 addrspace(1)* %c, i64 %idx.1.ext
  %a.1 = getelementptr inbounds i32, i32 addrspace(1)* %a, i64 %idx.1.ext

  %ld.c.0 = load i32, i32 addrspace(1)* %c.0, align 4
  store i32 %ld.c.0, i32 addrspace(1)* %a.0, align 4
  %ld.c.1 = load i32, i32 addrspace(1)* %c.1, align 4
  store i32 %ld.c.1, i32 addrspace(1)* %a.1, align 4

  %indvars.iv.next = add i64 %indvars.iv, 1
  %lftr.wideiv = trunc i64 %indvars.iv.next to i32

  %exitcond = icmp eq i32 %lftr.wideiv, %n
  br i1 %exitcond, label %exit, label %loop

exit:
  ret void
}

attributes #0 = { nounwind }
attributes #1 = { nounwind readnone }