; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt -passes=attributor -S < %s | FileCheck %s

define ptr @align_ptrmask_back_no_prop(ptr align 2 %x, i1 %cmp1, i1 %cmp2) {
; CHECK-LABEL: define noundef nonnull align 8 dereferenceable(4) ptr @align_ptrmask_back_no_prop(
; CHECK-SAME: ptr nofree writeonly align 2 [[X:%.*]], i1 [[CMP1:%.*]], i1 [[CMP2:%.*]]) #[[ATTR0:[0-9]+]] {
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP1]], i64 -32, i64 -8
; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[CMP2]], i64 [[SEL]], i64 -16
; CHECK-NEXT:    [[P:%.*]] = tail call noundef nonnull align 8 dereferenceable(4) ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 noundef [[SEL1]]) #[[ATTR4:[0-9]+]]
; CHECK-NEXT:    store float 1.000000e+00, ptr [[P]], align 8
; CHECK-NEXT:    ret ptr [[P]]
;
  %sel = select i1 %cmp1, i64 -32, i64 -8
  %sel1 = select i1 %cmp2, i64 %sel, i64 -16
  %p = tail call ptr @llvm.ptrmask.p0.i64(ptr %x, i64 %sel1)
  store float 1.0, ptr %p, align 8
  ret ptr %p
}

define ptr @align_ptrmask_back_prop(ptr align 2 %x, i1 %cmp1, i1 %cmp2) {
; CHECK-LABEL: define noundef nonnull align 16 dereferenceable(4) ptr @align_ptrmask_back_prop(
; CHECK-SAME: ptr nofree writeonly align 16 [[X:%.*]], i1 [[CMP1:%.*]], i1 [[CMP2:%.*]]) #[[ATTR0]] {
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP1]], i64 -32, i64 -8
; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[CMP2]], i64 [[SEL]], i64 -16
; CHECK-NEXT:    [[P:%.*]] = tail call noundef nonnull align 16 dereferenceable(4) ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 noundef [[SEL1]]) #[[ATTR4]]
; CHECK-NEXT:    store float 1.000000e+00, ptr [[P]], align 16
; CHECK-NEXT:    ret ptr [[P]]
;
  %sel = select i1 %cmp1, i64 -32, i64 -8
  %sel1 = select i1 %cmp2, i64 %sel, i64 -16
  %p = tail call ptr @llvm.ptrmask.p0.i64(ptr %x, i64 %sel1)
  store float 1.0, ptr %p, align 16
  ret ptr %p
}

define ptr @align_ptrmask_forward_mask(ptr align 2 %x, i1 %cmp1, i1 %cmp2) {
; CHECK-LABEL: define align 8 ptr @align_ptrmask_forward_mask(
; CHECK-SAME: ptr nofree readnone align 2 [[X:%.*]], i1 [[CMP1:%.*]], i1 [[CMP2:%.*]]) #[[ATTR1:[0-9]+]] {
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP1]], i64 -32, i64 -8
; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[CMP2]], i64 [[SEL]], i64 -16
; CHECK-NEXT:    [[P:%.*]] = tail call align 8 ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 noundef [[SEL1]]) #[[ATTR4]]
; CHECK-NEXT:    ret ptr [[P]]
;
  %sel = select i1 %cmp1, i64 -32, i64 -8
  %sel1 = select i1 %cmp2, i64 %sel, i64 -16
  %p = tail call ptr @llvm.ptrmask.p0.i64(ptr %x, i64 %sel1)
  ret ptr %p
}

define ptr @align_ptrmask_forward_ptr(ptr align 16 %x, i1 %cmp1, i1 %cmp2) {
; CHECK-LABEL: define align 16 ptr @align_ptrmask_forward_ptr(
; CHECK-SAME: ptr nofree readnone align 16 [[X:%.*]], i1 [[CMP1:%.*]], i1 [[CMP2:%.*]]) #[[ATTR1]] {
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP1]], i64 -32, i64 -8
; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[CMP2]], i64 [[SEL]], i64 -16
; CHECK-NEXT:    [[P:%.*]] = tail call align 16 ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 noundef [[SEL1]]) #[[ATTR4]]
; CHECK-NEXT:    ret ptr [[P]]
;
  %sel = select i1 %cmp1, i64 -32, i64 -8
  %sel1 = select i1 %cmp2, i64 %sel, i64 -16
  %p = tail call ptr @llvm.ptrmask.p0.i64(ptr %x, i64 %sel1)
  ret ptr %p
}

define ptr @align_ptrmask_forward_nonconst_mask(ptr align 8 %x, i64 %y, i1 %cmp1, i1 %cmp2) {
; CHECK-LABEL: define align 8 ptr @align_ptrmask_forward_nonconst_mask(
; CHECK-SAME: ptr nofree readnone align 8 [[X:%.*]], i64 [[Y:%.*]], i1 [[CMP1:%.*]], i1 [[CMP2:%.*]]) #[[ATTR1]] {
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP1]], i64 -32, i64 [[Y]]
; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[CMP2]], i64 [[SEL]], i64 -16
; CHECK-NEXT:    [[P:%.*]] = tail call align 8 ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 [[SEL1]]) #[[ATTR4]]
; CHECK-NEXT:    ret ptr [[P]]
;
  %sel = select i1 %cmp1, i64 -32, i64 %y
  %sel1 = select i1 %cmp2, i64 %sel, i64 -16
  %p = tail call ptr @llvm.ptrmask.p0.i64(ptr %x, i64 %sel1)
  ret ptr %p
}

define ptr @align_ptrmask_back_nonconst_mask(ptr align 4 %x, i64 %y, i1 %cmp1, i1 %cmp2) {
; CHECK-LABEL: define noundef nonnull align 8 dereferenceable(4) ptr @align_ptrmask_back_nonconst_mask(
; CHECK-SAME: ptr nofree writeonly align 8 [[X:%.*]], i64 [[Y:%.*]], i1 [[CMP1:%.*]], i1 [[CMP2:%.*]]) #[[ATTR0]] {
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP1]], i64 -32, i64 [[Y]]
; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[CMP2]], i64 [[SEL]], i64 -16
; CHECK-NEXT:    [[P:%.*]] = tail call noundef nonnull align 8 dereferenceable(4) ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 [[SEL1]]) #[[ATTR4]]
; CHECK-NEXT:    store float 1.000000e+00, ptr [[P]], align 8
; CHECK-NEXT:    ret ptr [[P]]
;
  %sel = select i1 %cmp1, i64 -32, i64 %y
  %sel1 = select i1 %cmp2, i64 %sel, i64 -16
  %p = tail call ptr @llvm.ptrmask.p0.i64(ptr %x, i64 %sel1)
  store float 1.0, ptr %p, align 8
  ret ptr %p
}

define ptr @align_ptrmask_back_const_back_noprop(ptr align 4 %x, i64 %y, i1 %cmp1, i1 %cmp2) {
; CHECK-LABEL: define noundef nonnull align 8 dereferenceable(4) ptr @align_ptrmask_back_const_back_noprop(
; CHECK-SAME: ptr nofree writeonly align 4 [[X:%.*]], i64 [[Y:%.*]], i1 [[CMP1:%.*]], i1 [[CMP2:%.*]]) #[[ATTR0]] {
; CHECK-NEXT:    [[P:%.*]] = tail call noundef nonnull align 8 dereferenceable(4) ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 noundef -8) #[[ATTR4]]
; CHECK-NEXT:    store float 1.000000e+00, ptr [[P]], align 8
; CHECK-NEXT:    ret ptr [[P]]
;
  %p = tail call ptr @llvm.ptrmask.p0.i64(ptr %x, i64 -8)
  store float 1.0, ptr %p, align 8
  ret ptr %p
}

define ptr @align_ptrmask_back_const_back_prop(ptr align 4 %x, i64 %y, i1 %cmp1, i1 %cmp2) {
; CHECK-LABEL: define noundef nonnull align 8 dereferenceable(4) ptr @align_ptrmask_back_const_back_prop(
; CHECK-SAME: ptr nofree writeonly align 8 [[X:%.*]], i64 [[Y:%.*]], i1 [[CMP1:%.*]], i1 [[CMP2:%.*]]) #[[ATTR0]] {
; CHECK-NEXT:    [[P:%.*]] = tail call noundef nonnull align 8 dereferenceable(4) ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 noundef -2) #[[ATTR4]]
; CHECK-NEXT:    store float 1.000000e+00, ptr [[P]], align 8
; CHECK-NEXT:    ret ptr [[P]]
;
  %p = tail call ptr @llvm.ptrmask.p0.i64(ptr %x, i64 -2)
  store float 1.0, ptr %p, align 8
  ret ptr %p
}

define ptr @align_ptrmask_back_const_forward_mask(ptr align 4 %x, i64 %y, i1 %cmp1, i1 %cmp2) {
; CHECK-LABEL: define align 8 ptr @align_ptrmask_back_const_forward_mask(
; CHECK-SAME: ptr nofree readnone align 4 [[X:%.*]], i64 [[Y:%.*]], i1 [[CMP1:%.*]], i1 [[CMP2:%.*]]) #[[ATTR1]] {
; CHECK-NEXT:    [[P:%.*]] = tail call align 8 ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 noundef -8) #[[ATTR4]]
; CHECK-NEXT:    ret ptr [[P]]
;
  %p = tail call ptr @llvm.ptrmask.p0.i64(ptr %x, i64 -8)
  ret ptr %p
}

define ptr @align_ptrmask_back_const_forward_ptr(ptr align 16 %x, i64 %y, i1 %cmp1, i1 %cmp2) {
; CHECK-LABEL: define align 16 ptr @align_ptrmask_back_const_forward_ptr(
; CHECK-SAME: ptr nofree readnone align 16 [[X:%.*]], i64 [[Y:%.*]], i1 [[CMP1:%.*]], i1 [[CMP2:%.*]]) #[[ATTR1]] {
; CHECK-NEXT:    [[P:%.*]] = tail call align 16 ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 noundef -8) #[[ATTR4]]
; CHECK-NEXT:    ret ptr [[P]]
;
  %p = tail call ptr @llvm.ptrmask.p0.i64(ptr %x, i64 -8)
  ret ptr %p
}

; FIXME: The store will create AAAlign for %ptr1,
; but the attribute didn't propagate through extractelement, need propagate
define <2 x ptr> @ptrmask_v2p0_v2i64(<2 x ptr> align 2 %ptr, i64 %a) {
; CHECK-LABEL: define <2 x ptr> @ptrmask_v2p0_v2i64(
; CHECK-SAME: <2 x ptr> align 2 [[PTR:%.*]], i64 [[A:%.*]]) #[[ATTR2:[0-9]+]] {
; CHECK-NEXT:    [[RESULT:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[PTR]], <2 x i64> noundef splat (i64 -8)) #[[ATTR4]]
; CHECK-NEXT:    [[PTR1:%.*]] = extractelement <2 x ptr> [[RESULT]], i32 0
; CHECK-NEXT:    [[PTR2:%.*]] = extractelement <2 x ptr> [[RESULT]], i32 1
; CHECK-NEXT:    store i64 [[A]], ptr [[PTR1]], align 16
; CHECK-NEXT:    store i64 [[A]], ptr [[PTR2]], align 16
; CHECK-NEXT:    ret <2 x ptr> [[RESULT]]
;
  %result = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %ptr, <2 x i64> splat(i64 -8))
  %ptr1 = extractelement <2 x ptr> %result, i32 0
  %ptr2 = extractelement <2 x ptr> %result, i32 1
  store i64 %a, ptr %ptr1, align 16
  store i64 %a, ptr %ptr2, align 16
  ret <2 x ptr> %result
}

define ptr @align_ptrmask_forward_mask_positive(ptr align 4 %x, i64 %y, i1 %cmp1, i1 %cmp2) {
; CHECK-LABEL: define align 4 ptr @align_ptrmask_forward_mask_positive(
; CHECK-SAME: ptr nofree readnone align 4 [[X:%.*]], i64 [[Y:%.*]], i1 [[CMP1:%.*]], i1 [[CMP2:%.*]]) #[[ATTR1]] {
; CHECK-NEXT:    [[P:%.*]] = tail call align 4 ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 noundef 2) #[[ATTR4]]
; CHECK-NEXT:    ret ptr [[P]]
;
  %p = tail call ptr @llvm.ptrmask.p0.i64(ptr %x, i64 2)
  ret ptr %p
}

define ptr @align_ptrmask_forward_mask_poison(ptr align 4 %x, i64 %y, i1 %cmp1, i1 %cmp2) {
; CHECK-LABEL: define align 4 ptr @align_ptrmask_forward_mask_poison(
; CHECK-SAME: ptr nofree readnone align 4 [[X:%.*]], i64 [[Y:%.*]], i1 [[CMP1:%.*]], i1 [[CMP2:%.*]]) #[[ATTR1]] {
; CHECK-NEXT:    [[P:%.*]] = tail call align 4 ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 poison) #[[ATTR4]]
; CHECK-NEXT:    ret ptr [[P]]
;
  %p = tail call ptr @llvm.ptrmask.p0.i64(ptr %x, i64 poison)
  ret ptr %p
}

define ptr @align_ptrmask_forward_mask_max(ptr align 4 %x, i64 %y, i1 %cmp1, i1 %cmp2) {
; CHECK-LABEL: define align 4294967296 ptr @align_ptrmask_forward_mask_max(
; CHECK-SAME: ptr nofree readnone align 4 [[X:%.*]], i64 [[Y:%.*]], i1 [[CMP1:%.*]], i1 [[CMP2:%.*]]) #[[ATTR1]] {
; CHECK-NEXT:    [[P:%.*]] = tail call align 4294967296 ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 noundef -4294967296) #[[ATTR4]]
; CHECK-NEXT:    ret ptr [[P]]
;
  %p = tail call ptr @llvm.ptrmask.p0.i64(ptr %x, i64 -4294967296)
  ret ptr %p
}

define ptr @align_ptrmask_forward_mask_max_plus_one(ptr align 4 %x, i64 %y, i1 %cmp1, i1 %cmp2) {
; CHECK-LABEL: define align 4294967296 ptr @align_ptrmask_forward_mask_max_plus_one(
; CHECK-SAME: ptr nofree readnone align 4 [[X:%.*]], i64 [[Y:%.*]], i1 [[CMP1:%.*]], i1 [[CMP2:%.*]]) #[[ATTR1]] {
; CHECK-NEXT:    [[P:%.*]] = tail call align 4294967296 ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 noundef -8589934592) #[[ATTR4]]
; CHECK-NEXT:    ret ptr [[P]]
;
  %p = tail call ptr @llvm.ptrmask.p0.i64(ptr %x, i64 -8589934592)
  ret ptr %p
}

define ptr @align_ptrmask_back_callsite(ptr align 4 %x, i64 %y, i1 %cmp1, i1 %cmp2) {
; CHECK-LABEL: define align 16 ptr @align_ptrmask_back_callsite(
; CHECK-SAME: ptr nofree readnone align 16 [[X:%.*]], i64 [[Y:%.*]], i1 [[CMP1:%.*]], i1 [[CMP2:%.*]]) #[[ATTR1]] {
; CHECK-NEXT:    [[P:%.*]] = tail call align 16 ptr @llvm.ptrmask.p0.i64(ptr [[X]], i64 noundef -4) #[[ATTR4]]
; CHECK-NEXT:    ret ptr [[P]]
;
  %p = tail call align 16 ptr @llvm.ptrmask.p0.i64(ptr %x, i64 -4)
  ret ptr %p
}
