; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
;=========================== begin_copyright_notice ============================
;
; Copyright (C) 2024 Intel Corporation
;
; SPDX-License-Identifier: MIT
;
;============================ end_copyright_notice =============================
;
; REQUIRES: regkeys
; RUN: igc_opt --igc-scalarize --opaque-pointers -S --regkey=EnableSelectiveScalarizer=1 < %s | FileCheck %s
; REQUIRES: llvm-14-plus
; ------------------------------------------------
; ScalarizeFunction
; ------------------------------------------------
; This test checks if selective scalarization leaves vectorial instructions un-scalarized.
; ------------------------------------------------

define spir_kernel void @test_selective_1(i64 %addr) #0 {
; CHECK-LABEL: define spir_kernel void @test_selective_1(
; CHECK-SAME: i64 [[ADDR:%.*]]) #[[ATTR0:[0-9]+]] {
; CHECK-NEXT:    [[VECTINT:%.*]] = add <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>, zeroinitializer
; CHECK-NEXT:    [[VECTFLOAT:%.*]] = bitcast <8 x i32> [[VECTINT]] to <8 x float>
; CHECK-NEXT:    [[VECTCAST:%.*]] = bitcast <8 x float> [[VECTFLOAT]] to <8 x i32>
; CHECK-NEXT:    call void @llvm.genx.GenISA.LSC2DBlockWrite.v8i32(i64 [[ADDR]], i32 1023, i32 511, i32 1023, i32 0, i32 0, i32 32, i32 16, i32 8, i32 1, i1 false, i1 false, i32 0, <8 x i32> [[VECTCAST]])
; CHECK-NEXT:    ret void
;

; define a vector and do some bitcasts
; nothing should get scalarized here

  %vectint = add <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>, zeroinitializer
  %vectfloat = bitcast <8 x i32> %vectint to <8 x float>
  %vectcast = bitcast <8 x float> %vectfloat to <8 x i32>
  call void @llvm.genx.GenISA.LSC2DBlockWrite.v8i32(i64 %addr, i32 1023, i32 511, i32 1023, i32 0, i32 0, i32 32, i32 16, i32 8, i32 1, i1 false, i1 false, i32 0, <8 x i32> %vectcast)

  ret void
}

define spir_kernel void @test_selective_2(i64 %addr) #0 {
; CHECK-LABEL: define spir_kernel void @test_selective_2(
; CHECK-SAME: i64 [[ADDR:%.*]]) #[[ATTR0]] {
; CHECK-NEXT:    [[VECTINT:%.*]] = add <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>, zeroinitializer
; CHECK-NEXT:    [[VECTFLOAT:%.*]] = bitcast <8 x i32> [[VECTINT]] to <8 x float>
; CHECK-NEXT:    [[VECTCAST:%.*]] = bitcast <8 x float> [[VECTFLOAT]] to <8 x i32>
; CHECK-NEXT:    call void @llvm.genx.GenISA.LSC2DBlockWrite.v8i32(i64 [[ADDR]], i32 1023, i32 511, i32 1023, i32 0, i32 0, i32 32, i32 16, i32 8, i32 1, i1 false, i1 false, i32 0, <8 x i32> [[VECTCAST]])
; CHECK-NEXT:    [[ANOTHERCAST:%.*]] = bitcast <8 x float> [[VECTFLOAT]] to <8 x i32>
; CHECK-NEXT:    [[ANOTHERCAST_SCALAR:%.*]] = extractelement <8 x i32> [[ANOTHERCAST]], i32 0
; CHECK-NEXT:    [[ANOTHERCAST_SCALAR1:%.*]] = extractelement <8 x i32> [[ANOTHERCAST]], i32 1
; CHECK-NEXT:    [[ANOTHERCAST_SCALAR2:%.*]] = extractelement <8 x i32> [[ANOTHERCAST]], i32 2
; CHECK-NEXT:    [[ANOTHERCAST_SCALAR3:%.*]] = extractelement <8 x i32> [[ANOTHERCAST]], i32 3
; CHECK-NEXT:    [[ANOTHERCAST_SCALAR4:%.*]] = extractelement <8 x i32> [[ANOTHERCAST]], i32 4
; CHECK-NEXT:    [[ANOTHERCAST_SCALAR5:%.*]] = extractelement <8 x i32> [[ANOTHERCAST]], i32 5
; CHECK-NEXT:    [[ANOTHERCAST_SCALAR6:%.*]] = extractelement <8 x i32> [[ANOTHERCAST]], i32 6
; CHECK-NEXT:    [[ANOTHERCAST_SCALAR7:%.*]] = extractelement <8 x i32> [[ANOTHERCAST]], i32 7
; CHECK-NEXT:    [[V3:%.*]] = add i32 [[ANOTHERCAST_SCALAR3]], [[ANOTHERCAST_SCALAR5]]
; CHECK-NEXT:    ret void
;
; same as before, but %vectfloat is used in another branch of the code
  %vectint = add <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>, zeroinitializer
  %vectfloat = bitcast <8 x i32> %vectint to <8 x float>
  %vectcast = bitcast <8 x float> %vectfloat to <8 x i32>
  call void @llvm.genx.GenISA.LSC2DBlockWrite.v8i32(i64 %addr, i32 1023, i32 511, i32 1023, i32 0, i32 0, i32 32, i32 16, i32 8, i32 1, i1 false, i1 false, i32 0, <8 x i32> %vectcast)
; so scalarization should happen here
  %anothercast = bitcast <8 x float> %vectfloat to <8 x i32>
  %v1 = extractelement <8 x i32> %anothercast, i32 3
  %v2 = extractelement <8 x i32> %anothercast, i32 5
  %v3 = add i32 %v1, %v2
  ret void
}

define spir_kernel void @test_selective_3() {
; CHECK-LABEL: define spir_kernel void @test_selective_3() {
; CHECK-NEXT:    br label %[[LOOP:.*]]
; CHECK:       [[LOOP]]:
; CHECK-NEXT:    [[OFFSET:%.*]] = phi i32 [ 0, [[TMP0:%.*]] ], [ [[NEWOFFSET:%.*]], %[[LOOP]] ]
; CHECK-NEXT:    [[DATA:%.*]] = phi <8 x i32> [ zeroinitializer, [[TMP0]] ], [ [[NEWDATA:%.*]], %[[LOOP]] ]
; CHECK-NEXT:    [[NEWDATA]] = call <8 x i32> @do_math_v8i32_v8i32(<8 x i32> [[DATA]])
; CHECK-NEXT:    [[NEWOFFSET]] = add i32 [[OFFSET]], 1
; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i32 [[NEWOFFSET]], 10
; CHECK-NEXT:    br i1 [[TMP1]], label %[[END:.*]], label %[[LOOP]]
; CHECK:       [[END]]:
; CHECK-NEXT:    ret void
;

; no scalarization happens here because the vectors %data and %newdata are used as whole
  br label %loop

loop:
  %offset  = phi i32 [ 0, %0 ], [ %newoffset, %loop ]

  %data    = phi <8 x i32> [ zeroinitializer, %0 ], [ %newdata, %loop ]
  %newdata = call <8 x i32> @do_math_v8i32_v8i32(<8 x i32> %data)

  %newoffset = add i32 %offset, 1
  %1 = icmp eq i32 %newoffset, 10
  br i1 %1, label %end, label %loop

end:
  ret void
}

define spir_kernel void @test_selective_4(i64 %addr) #0 {
; CHECK-LABEL: define spir_kernel void @test_selective_4(
; CHECK-SAME: i64 [[ADDR:%.*]]) #[[ATTR0]] {
; CHECK-NEXT:    br label %[[LOOP:.*]]
; CHECK:       [[LOOP]]:
; CHECK-NEXT:    [[OFFSET:%.*]] = phi i32 [ 0, [[TMP0:%.*]] ], [ [[NEWOFFSET:%.*]], %[[LOOP]] ]
; CHECK-NEXT:    [[FLOAT_VECTOR:%.*]] = phi <8 x float> [ zeroinitializer, [[TMP0]] ], [ [[NEW_FLOAT_VECTOR:%.*]], %[[LOOP]] ]
; CHECK-NEXT:    [[INT_VECTOR:%.*]] = call <8 x i32> @llvm.genx.GenISA.LSC2DBlockRead.v8i32(i64 [[ADDR]], i32 1023, i32 511, i32 1023, i32 [[OFFSET]], i32 0, i32 32, i32 16, i32 8, i32 1, i1 false, i1 false, i32 0)
; CHECK-NEXT:    [[NEW_FLOAT_VECTOR]] = call <8 x float> @llvm.genx.GenISA.sub.group.dpas.v8f32.v8f32.v8i16.v8i32(<8 x float> [[FLOAT_VECTOR]], <8 x i16> <i16 0, i16 1, i16 2, i16 3, i16 4, i16 5, i16 6, i16 7>, <8 x i32> [[INT_VECTOR]], i32 11, i32 11, i32 8, i32 8, i1 false)
; CHECK-NEXT:    [[NEWOFFSET]] = add i32 [[OFFSET]], 16
; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i32 [[NEWOFFSET]], 256
; CHECK-NEXT:    br i1 [[TMP1]], label %[[END:.*]], label %[[LOOP]]
; CHECK:       [[END]]:
; CHECK-NEXT:    ret void
;

; same here: no scalarization
  br label %loop

loop:
  %offset = phi i32 [ 0, %0 ], [ %newoffset, %loop ]
  %float_vector = phi <8 x float> [ zeroinitializer, %0 ], [ %new_float_vector, %loop ]
  %int_vector = call <8 x i32> @llvm.genx.GenISA.LSC2DBlockRead.v8i32(i64 %addr, i32 1023, i32 511, i32 1023, i32 %offset, i32 0, i32 32, i32 16, i32 8, i32 1, i1 false, i1 false, i32 0)
  %new_float_vector = call <8 x float> @llvm.genx.GenISA.sub.group.dpas.v8f32.v8f32.v8i16.v8i32(<8 x float> %float_vector, <8 x i16> <i16 0, i16 1, i16 2, i16 3, i16 4, i16 5, i16 6, i16 7>, <8 x i32> %int_vector, i32 11, i32 11, i32 8, i32 8, i1 false)
  %newoffset = add i32 %offset, 16
  %1 = icmp eq i32 %newoffset, 256
  br i1 %1, label %end, label %loop

end:
  ret void
}


define spir_kernel void @test_selective_5() {
; CHECK-LABEL: define spir_kernel void @test_selective_5() {
; CHECK-NEXT:    br label %[[LOOP:.*]]
; CHECK:       [[LOOP]]:
; CHECK-NEXT:    [[OFFSET:%.*]] = phi i32 [ 0, [[TMP0:%.*]] ], [ [[NEWOFFSET:%.*]], %[[LOOP]] ]
; CHECK-NEXT:    [[DATA1:%.*]] = phi i32 [ 0, [[TMP0]] ], [ [[NEWDATA_SCALAR:%.*]], %[[LOOP]] ]
; CHECK-NEXT:    [[DATA3:%.*]] = phi i32 [ 0, [[TMP0]] ], [ [[NEWDATA_SCALAR10:%.*]], %[[LOOP]] ]
; CHECK-NEXT:    [[DATA4:%.*]] = phi i32 [ 0, [[TMP0]] ], [ [[NEWDATA_SCALAR11:%.*]], %[[LOOP]] ]
; CHECK-NEXT:    [[DATA5:%.*]] = phi i32 [ 0, [[TMP0]] ], [ [[NEWDATA_SCALAR12:%.*]], %[[LOOP]] ]
; CHECK-NEXT:    [[DATA6:%.*]] = phi i32 [ 0, [[TMP0]] ], [ undef, %[[LOOP]] ]
; CHECK-NEXT:    [[DATA7:%.*]] = phi i32 [ 0, [[TMP0]] ], [ undef, %[[LOOP]] ]
; CHECK-NEXT:    [[DATA8:%.*]] = phi i32 [ 0, [[TMP0]] ], [ undef, %[[LOOP]] ]
; CHECK-NEXT:    [[DATA9:%.*]] = phi i32 [ 0, [[TMP0]] ], [ undef, %[[LOOP]] ]
; CHECK-NEXT:    [[DATA2_ASSEMBLED_VECT:%.*]] = insertelement <4 x i32> undef, i32 [[DATA1]], i32 0
; CHECK-NEXT:    [[DATA2_ASSEMBLED_VECT13:%.*]] = insertelement <4 x i32> [[DATA2_ASSEMBLED_VECT]], i32 [[DATA3]], i32 1
; CHECK-NEXT:    [[DATA2_ASSEMBLED_VECT14:%.*]] = insertelement <4 x i32> [[DATA2_ASSEMBLED_VECT13]], i32 [[DATA4]], i32 2
; CHECK-NEXT:    [[DATA2_ASSEMBLED_VECT15:%.*]] = insertelement <4 x i32> [[DATA2_ASSEMBLED_VECT14]], i32 [[DATA5]], i32 3
; CHECK-NEXT:    [[NEWDATA:%.*]] = call <4 x i32> @do_math_v4i32_v4i32(<4 x i32> [[DATA2_ASSEMBLED_VECT15]])
; CHECK-NEXT:    [[NEWDATA_SCALAR]] = extractelement <4 x i32> [[NEWDATA]], i32 0
; CHECK-NEXT:    [[NEWDATA_SCALAR10]] = extractelement <4 x i32> [[NEWDATA]], i32 1
; CHECK-NEXT:    [[NEWDATA_SCALAR11]] = extractelement <4 x i32> [[NEWDATA]], i32 2
; CHECK-NEXT:    [[NEWDATA_SCALAR12]] = extractelement <4 x i32> [[NEWDATA]], i32 3
; CHECK-NEXT:    [[NEWOFFSET]] = add i32 [[OFFSET]], 1
; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i32 [[NEWOFFSET]], 10
; CHECK-NEXT:    br i1 [[TMP1]], label %[[END:.*]], label %[[LOOP]]
; CHECK:       [[END]]:
; CHECK-NEXT:    ret void
;

; here shufflevectors break vectorial nature of the arguments
; scalarization should be done
  br label %loop

loop:
  %offset   = phi i32 [ 0, %0 ], [ %newoffset, %loop ]

  %data     = phi <8 x i32> [ zeroinitializer, %0 ], [ %newdata2, %loop ]
  %data2    = shufflevector <8 x i32> %data, <8 x i32> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
  %newdata  = call <4 x i32> @do_math_v4i32_v4i32(<4 x i32> %data2)
  %newdata2 = shufflevector <4 x i32> %newdata, <4 x i32> undef, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef>

  %newoffset = add i32 %offset, 1
  %1 = icmp eq i32 %newoffset, 10
  br i1 %1, label %end, label %loop

end:
  ret void
}

define spir_kernel void @test_selective_6() {
; CHECK-LABEL: define spir_kernel void @test_selective_6() {
; CHECK-NEXT:    br label %[[LOOP:.*]]
; CHECK:       [[LOOP]]:
; CHECK-NEXT:    [[OFFSET:%.*]] = phi i32 [ 0, [[TMP0:%.*]] ], [ [[NEWOFFSET:%.*]], %[[LOOP]] ]
; CHECK-NEXT:    [[VECTFLOAT1:%.*]] = phi float [ 0.000000e+00, [[TMP0]] ], [ [[VECTFLOAT_NEXT25:%.*]], %[[LOOP]] ]
; CHECK-NEXT:    [[VECTFLOAT2:%.*]] = phi float [ 0.000000e+00, [[TMP0]] ], [ [[VECTFLOAT_NEXT26:%.*]], %[[LOOP]] ]
; CHECK-NEXT:    [[VECTFLOAT3:%.*]] = phi float [ 0.000000e+00, [[TMP0]] ], [ [[VECTFLOAT_NEXT27:%.*]], %[[LOOP]] ]
; CHECK-NEXT:    [[VECTFLOAT4:%.*]] = phi float [ 0.000000e+00, [[TMP0]] ], [ [[VECTFLOAT_NEXT28:%.*]], %[[LOOP]] ]
; CHECK-NEXT:    [[VECTFLOAT5:%.*]] = phi float [ 0.000000e+00, [[TMP0]] ], [ [[VECTFLOAT_NEXT29:%.*]], %[[LOOP]] ]
; CHECK-NEXT:    [[VECTFLOAT6:%.*]] = phi float [ 0.000000e+00, [[TMP0]] ], [ [[VECTFLOAT_NEXT30:%.*]], %[[LOOP]] ]
; CHECK-NEXT:    [[VECTFLOAT7:%.*]] = phi float [ 0.000000e+00, [[TMP0]] ], [ [[VECTFLOAT_NEXT31:%.*]], %[[LOOP]] ]
; CHECK-NEXT:    [[VECTFLOAT8:%.*]] = phi float [ 0.000000e+00, [[TMP0]] ], [ [[VECTFLOAT_NEXT32:%.*]], %[[LOOP]] ]
; CHECK-NEXT:    [[VECTINT9:%.*]] = bitcast float [[VECTFLOAT1]] to i32
; CHECK-NEXT:    [[VECTINT10:%.*]] = bitcast float [[VECTFLOAT2]] to i32
; CHECK-NEXT:    [[VECTINT11:%.*]] = bitcast float [[VECTFLOAT3]] to i32
; CHECK-NEXT:    [[VECTINT12:%.*]] = bitcast float [[VECTFLOAT4]] to i32
; CHECK-NEXT:    [[VECTINT13:%.*]] = bitcast float [[VECTFLOAT5]] to i32
; CHECK-NEXT:    [[VECTINT14:%.*]] = bitcast float [[VECTFLOAT6]] to i32
; CHECK-NEXT:    [[VECTINT15:%.*]] = bitcast float [[VECTFLOAT7]] to i32
; CHECK-NEXT:    [[VECTINT16:%.*]] = bitcast float [[VECTFLOAT8]] to i32
; CHECK-NEXT:    [[VECTADD17:%.*]] = add i32 [[VECTINT9]], 1
; CHECK-NEXT:    [[VECTADD18:%.*]] = add i32 [[VECTINT10]], 2
; CHECK-NEXT:    [[VECTADD19:%.*]] = add i32 [[VECTINT11]], 3
; CHECK-NEXT:    [[VECTADD20:%.*]] = add i32 [[VECTINT12]], 4
; CHECK-NEXT:    [[VECTADD21:%.*]] = add i32 [[VECTINT13]], 5
; CHECK-NEXT:    [[VECTADD22:%.*]] = add i32 [[VECTINT14]], 6
; CHECK-NEXT:    [[VECTADD23:%.*]] = add i32 [[VECTINT15]], 7
; CHECK-NEXT:    [[VECTADD24:%.*]] = add i32 [[VECTINT16]], 8
; CHECK-NEXT:    [[VECTFLOAT_NEXT25]] = bitcast i32 [[VECTADD17]] to float
; CHECK-NEXT:    [[VECTFLOAT_NEXT26]] = bitcast i32 [[VECTADD18]] to float
; CHECK-NEXT:    [[VECTFLOAT_NEXT27]] = bitcast i32 [[VECTADD19]] to float
; CHECK-NEXT:    [[VECTFLOAT_NEXT28]] = bitcast i32 [[VECTADD20]] to float
; CHECK-NEXT:    [[VECTFLOAT_NEXT29]] = bitcast i32 [[VECTADD21]] to float
; CHECK-NEXT:    [[VECTFLOAT_NEXT30]] = bitcast i32 [[VECTADD22]] to float
; CHECK-NEXT:    [[VECTFLOAT_NEXT31]] = bitcast i32 [[VECTADD23]] to float
; CHECK-NEXT:    [[VECTFLOAT_NEXT32]] = bitcast i32 [[VECTADD24]] to float
; CHECK-NEXT:    [[NEWOFFSET]] = add i32 [[OFFSET]], 1
; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i32 [[NEWOFFSET]], 10
; CHECK-NEXT:    br i1 [[TMP1]], label %[[END:.*]], label %[[LOOP]]
; CHECK:       [[END]]:
; CHECK-NEXT:    ret void
;

; scalarization should not be prevented due to elementwise bitcasts
; such bitcasts can be part of a chain of vector instructions, but
; should not be at the end of it
  br label %loop

loop:
  %offset = phi i32 [ 0, %0 ], [ %newoffset, %loop ]
  %vectfloat = phi <8 x float> [ zeroinitializer, %0 ], [ %vectfloat.next, %loop ]

  %vectint = bitcast <8 x float> %vectfloat to <8 x i32>
  %vectadd = add <8 x i32> %vectint, <i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8>
  %vectfloat.next = bitcast <8 x i32> %vectadd to <8 x float>

  %newoffset = add i32 %offset, 1
  %1 = icmp eq i32 %newoffset, 10
  br i1 %1, label %end, label %loop
end:
  ret void
}

define spir_kernel void @test_selective_7() {
; CHECK-LABEL: define spir_kernel void @test_selective_7() {
; CHECK-NEXT:    [[VECTINT:%.*]] = add <4 x i16> <i16 0, i16 1, i16 2, i16 3>, zeroinitializer
; CHECK-NEXT:    [[VECTFLOAT:%.*]] = bitcast <4 x i16> [[VECTINT]] to <4 x half>
; CHECK-NEXT:    [[VECTCAST:%.*]] = bitcast <4 x half> [[VECTFLOAT]] to i64
; CHECK-NEXT:    ret void
;

; non-elementwise bitcasts (result type is scalar) should prevent scalarization,
; thus no scalarization should happen here
  %vectint = add <4 x i16> <i16 0, i16 1, i16 2, i16 3>, zeroinitializer
  %vectfloat = bitcast <4 x i16> %vectint to <4 x half>
  %vectcast = bitcast <4 x half> %vectfloat to i64

  ret void
}

define spir_kernel void @test_selective_8() {
; CHECK-LABEL: define spir_kernel void @test_selective_8() {
; CHECK-NEXT:    [[VECTINT:%.*]] = add <4 x i16> <i16 0, i16 1, i16 2, i16 3>, zeroinitializer
; CHECK-NEXT:    [[VECTFLOAT:%.*]] = bitcast <4 x i16> [[VECTINT]] to <4 x half>
; CHECK-NEXT:    [[VECTCAST:%.*]] = bitcast <4 x half> [[VECTFLOAT]] to <2 x i32>
; CHECK-NEXT:    ret void
;

; non-elementwise bitcasts (result is different sized vector) should prevent scalarization,
; thus no scalarization should happen here
  %vectint = add <4 x i16> <i16 0, i16 1, i16 2, i16 3>, zeroinitializer
  %vectfloat = bitcast <4 x i16> %vectint to <4 x half>
  %vectcast = bitcast <4 x half> %vectfloat to <2 x i32>

  ret void
}

define <32 x i1> @test_selective_9(i64 %addr) #0 {
; CHECK-LABEL: define <32 x i1> @test_selective_9(
; CHECK-SAME: i64 [[ADDR:%.*]]) #[[ATTR0]] {
; CHECK-NEXT:    [[INT:%.*]] = add i32 1, 0
; CHECK-NEXT:    [[FLOAT:%.*]] = bitcast i32 [[INT]] to float
; CHECK-NEXT:    [[VECTCAST:%.*]] = bitcast float [[FLOAT]] to <32 x i1>
; CHECK-NEXT:    ret <32 x i1> [[VECTCAST]]
;
  %int = add i32 1, zeroinitializer
  %float = bitcast i32 %int to float
  %vectcast = bitcast float %float to <32 x i1>
  ret <32 x i1> %vectcast
}

define <2 x i32> @should_not_scalarize_if_the_index_is_not_a_constant(i32 %src) {
; CHECK-LABEL: define <2 x i32> @should_not_scalarize_if_the_index_is_not_a_constant(
; CHECK-SAME: i32 [[SRC:%.*]]) {
; CHECK-NEXT:    [[VECTOR_ASSEMBLED_VECT:%.*]] = insertelement <2 x i32> undef, i32 [[SRC]], i32 0
; CHECK-NEXT:    [[VECTOR_ASSEMBLED_VECT1:%.*]] = insertelement <2 x i32> [[VECTOR_ASSEMBLED_VECT]], i32 undef, i32 1
; CHECK-NEXT:    [[RESULT:%.*]] = insertelement <2 x i32> [[VECTOR_ASSEMBLED_VECT1]], i32 3, i32 [[SRC]]
; CHECK-NEXT:    ret <2 x i32> [[RESULT]]
;
  %vector = insertelement <2 x i32> undef, i32 %src, i32 0
  %result = insertelement <2 x i32> %vector, i32 3, i32 %src
  ret <2 x i32> %result
}

define i32 @should_not_scalarize_if_the_index_is_not_a_constant_2(i32 %src) {
; CHECK-LABEL: define i32 @should_not_scalarize_if_the_index_is_not_a_constant_2(
; CHECK-SAME: i32 [[SRC:%.*]]) {
; CHECK-NEXT:    [[VECTOR_ASSEMBLED_VECT:%.*]] = insertelement <2 x i32> undef, i32 [[SRC]], i32 0
; CHECK-NEXT:    [[VECTOR_ASSEMBLED_VECT1:%.*]] = insertelement <2 x i32> [[VECTOR_ASSEMBLED_VECT]], i32 undef, i32 1
; CHECK-NEXT:    [[RESULT:%.*]] = extractelement <2 x i32> [[VECTOR_ASSEMBLED_VECT1]], i32 [[SRC]]
; CHECK-NEXT:    ret i32 [[RESULT]]
;
  %vector = insertelement <2 x i32> undef, i32 %src, i32 0
  %result = extractelement <2 x i32> %vector, i32 %src
  ret i32 %result
}

define spir_kernel void @should_not_scalarize_nested_phi(i1 %switch) {
; CHECK-LABEL: define spir_kernel void @should_not_scalarize_nested_phi(
; CHECK-SAME: i1 [[SWITCH:%.*]]) {
; CHECK-NEXT:  [[ENTRY:.*]]:
; CHECK-NEXT:    [[VECTINT:%.*]] = add <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>, zeroinitializer
; CHECK-NEXT:    br i1 [[SWITCH]], label %[[FIRST:.*]], label %[[SECOND:.*]]
; CHECK:       [[PROXY:.*]]:
; CHECK-NEXT:    br i1 [[SWITCH]], label %[[FIRST]], label %[[SECOND]]
; CHECK:       [[FIRST]]:
; CHECK-NEXT:    [[RESULT1:%.*]] = phi <8 x i32> [ zeroinitializer, %[[PROXY]] ], [ [[VECTINT]], %[[ENTRY]] ]
; CHECK-NEXT:    br label %[[EXIT:.*]]
; CHECK:       [[SECOND]]:
; CHECK-NEXT:    [[RESULT2:%.*]] = phi <8 x i32> [ zeroinitializer, %[[PROXY]] ], [ [[VECTINT]], %[[ENTRY]] ]
; CHECK-NEXT:    br label %[[EXIT]]
; CHECK:       [[EXIT]]:
; CHECK-NEXT:    [[RESULT3:%.*]] = phi <8 x i32> [ [[RESULT1]], %[[FIRST]] ], [ [[RESULT2]], %[[SECOND]] ]
; CHECK-NEXT:    [[NEWDATA:%.*]] = call <8 x i32> @do_math_v8i32_v8i32(<8 x i32> [[RESULT3]])
; CHECK-NEXT:    ret void
;
entry:
  %vectint = add <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>, zeroinitializer
  br i1 %switch, label %first, label %second
proxy:
  br i1 %switch, label %first, label %second
first:
  %result1 = phi <8 x i32> [ zeroinitializer, %proxy ], [ %vectint, %entry]
  br label %exit
second:
  %result2 = phi <8 x i32> [ zeroinitializer, %proxy ], [ %vectint, %entry]
  br label %exit
exit:
  %result3 = phi <8 x i32> [ %result1, %first], [ %result2, %second]
  %newdata = call <8 x i32> @do_math_v8i32_v8i32(<8 x i32> %result3)
  ret void
}

declare spir_func void @llvm.genx.GenISA.LSC2DBlockWrite.v8i32(i64, i32, i32, i32, i32, i32, i32, i32, i32, i32, i1, i1, i32, <8 x i32>) #1
declare spir_func <8 x i32> @llvm.genx.GenISA.LSC2DBlockRead.v8i32(i64, i32, i32, i32, i32, i32, i32, i32, i32, i32, i1, i1, i32) #1
declare spir_func <8 x float> @llvm.genx.GenISA.sub.group.dpas.v8f32.v8f32.v8i16.v8i32(<8 x float>, <8 x i16>, <8 x i32>, i32, i32, i32, i32, i1) #1
declare spir_func <4 x i32> @do_math_v4i32_v4i32(<4 x i32>) #1
declare spir_func <8 x i32> @do_math_v8i32_v8i32(<8 x i32>) #1

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